| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Welcome to X1Plus! If you're a user, you probably want to go straight to the wiki, which tells you everything you need to know about installing and using X1Plus on your printer.
The rest of this file has boring stuff for really big nerds who want to develop X1Plus.
Ok, don't say I didn't warn you. Anyway, hi! Glad you're interested in contributing to X1Plus! Here is a bunch of information on how to build it, how it's structured internally, and various things you might need to know about how to make changes and how to contribute back. X1Plus is the result of a year or so of vaguely-structured work; it started life as a fairly frumious hack, and over the past few months, we've been working hard to try to clean it up for release to the outside world. All that said, there are parts that you will find are still a mess, and for that, we're truly sorry! We hope you'll come play around with it anyway. There's a lot of fun stuff to be done, and we have only barely scratched the surface so far.
Probably the easiest way to get started building X1Plus is in a Docker container. If you're adventurous, you can probably build X1Plus on any old Linux machine (I do), but if you do that and it breaks, we really don't want to hear about it, so you really should just build it in Docker. You'll need the filesystem decryption key from a live printer (running either X1Plus or the Official Rootable Firmware) in order to build X1Plus.
Note that if you're on Windows you'd need to install Windows Subsystem for Linux:
wsl --install wsl -d Ubuntu
First, copy the getkey bin over to the printer:
scp scripts/getkey root@<printer’s IP>:/tmp
Now retrieve the key:
ssh root@<printer’s IP> /tmp/getkey >> localconfig.mk
Clone down the X1Plus repo and build the Docker image from the Dockerfile in scripts/docker. Please note: if you're using ARM or Apple Silicon you need to add --platform=linux/amd64 to your commands. In that case, use the second set of commands below:
$ git clone ... $ cd X1Plus $ docker build -t x1plusbuild scripts/docker/
For Apple Silicon:
$ git clone ... $ cd X1Plus $ docker buildx build --platform=linux/amd64 -t x1plusbuild scripts/docker/
In order to make on the Docker container a safe directory must be added to the git config. As that will only persist for one run the Docker container must be run in interactive mode. As above, run should be called with the --platform flag if you're running on an ARM or Apple Silicon chip. See the second command.
$ docker run -dit -v `pwd`:/work --name x1plusmake x1plusbuild
Apple Silicon:
$ docker run --platform=linux/amd64 -dit -v `pwd`:/work --name x1plusmake x1plusbuild
Now, exec into the Docker container and run the make commands. These commands vary depending on your platform:
###For Mac users:
$ docker exec -w /work x1plusmake bash -c 'git config --global \ --add safe.directory /work' $ docker exec -w /work x1plusmake make scripts $ docker exec -w /work x1plusmake make
###For Linux users:
$ docker run -u `id -u` -v `pwd`:/work x1plusbuild bash -c 'git config --global \ --add safe.directory /work' $ docker run -u `id -u` -v `pwd`:/work x1plusbuild make scripts $ docker run -u `id -u` -v `pwd`:/work x1plusbuild make
With some luck, you should get a .x1p file in your working directory! Get the name of that file:
$ docker exec -v `pwd`:/work x1plusmake sh -c 'ls /work | grep .x1p' $ <somefilename>.x1p
Copy that out of the Docker container.
$ docker cp x1plusmake:/work/<somefilename>.x1p
And scp it to the printer (never remove an SD card from a live X1Plus system, you goofball).
scp <somefilename>.x1p root@<printer’s IP>:/sdcard
Reboot your printer, and install X1Plus from the menu.
Finally, don't forget to stop your Docker container!
docker stop x1plusmake
If you're going to make changes to any of the UI files, you should really read the rest of this document... otherwise you might be in for a nasty surprise next time you git pull.
The core concept of X1Plus is that we build an overlay on top of the Bambu Lab firmware, and replace only the parts that we need in order to launch X1Plus. We are very careful not to redistribute any of Bambu Lab's IP directly; when it's necessary to use or patch Bambu Lab binaries, we download them directly from Bambu Lab servers, and then patch them onboard the printer. We also try to be pretty careful to leave the printer in a "fail-safe" state by modifying as little of the on-printer flash as possible. Below is a rough flow of how X1Plus works, from installer through to normal boot.
Host-side installer. The host-side installer is an Electron app that wraps all the logic to check whether the printer is running a supported version of the base firmware, and that wraps the mechanics of logging into the printer over MQTT, over FTP, and over SSH. (In development versions of X1Plus that relied on exploits to install, the PC-side installer was somewhat more complicated!) Roughly, this is implemented in installer-clientside/install-gui/src/index.ts.
The installer copies an .x1p image to the SD card, as well as a small tarball containing the on-printer install GUI stub. It SSHes to the printer, unpacks the tarball into /userdata on the printer, and runs a first-stage installer launch script that it (hopefully) unpacked; then, it waits for MQTT messages that indicate the progress of the installation.
First-stage install scripts. The first-stage installer (implemented in installer-clientside/stage1/x1plus/launch.sh) first shuts down the printer's service checker (otherwise, the GUI would get restarted!), and then shuts down the GUI. It drops a marker for the host-side installer to indicate that it has started up, and then relaunches the printer's GUI engine with X1Plus's setup GUI injected into it to replace the normal printer GUI.
X1Plus setup GUI. The precise mechanism by which we inject code into the GUI is interesting, but it is somewhat getting ahead of ourselves to discuss it exactly at this moment :) I'll talk about that in a moment. For now, all you really need to know is that this is implemented in QML, with bbl_screen-patch/kexec_ui/printerui/qml/Screen.qml as the initial item (the C++ native components live in bbl_screen-patch/interpose.cpp). As you might suspect from the name, this GUI is also part of the X1Plus boot process, but the first-stage installer launches it in such a way that the GUI goes straight into the installer screen. The installer mechanism, the SelectX1pPage, looks for .x1p images on the SD card, and asks the user which x1p to install. (An x1p is just a zip file that has an info.json and a payload.tar.gz in it.) Once the user chooses an x1p file, InstallingPage unpacks the payload.tar.gz into /userdata, invokes the Python-based install backend, and begins listening for DDS messages with status updates. (DDS is an internal pubsub message bus.)
Python install backend. The mechanics of what the Python installer does is probably better served by reading the code for it, which is in installer/install.py. We drop a precompiled version of Python into /userdata, and to communicate with the DDS message bus, we use ctypes to talk to the DDS system libraries. Roughly, the Python installer:
(You can read the details of each of those in the Python installer itself.) When installation is complete, the printer reboots into the slightly modified internal filesystem.
On boot: SD card check and GUI display. When the printer powers up, it boots first into the onboard eMMC installation, as normal. We inject a shell script into /etc/init.d/S75kexec, which subsequently launches /opt/kexec/check_kexec. (Both of these scripts live in internal-fs/ in this tree.) This script checks an "emergency override" (engaged by pressing and holding the POWER and ESTOP buttons while powering the printer up), and if those buttons are pressed, it quits as quickly as possible to return control to the internal printer firmware. Otherwise, it launches the same GUI as was used in the X1Plus Setup process above, and offers to either boot into SD card firmware or run advanced options. (Because it was launched from the actual boot process, the dialog/KexecDialog is presented, rather than the SelectX1pPage.) If the user chooses to boot from the SD card, the shell script /opt/kexec/boot runs and prepares to boot the printer into the new kernel.
kexec'ing into the new world. Things start getting weird here, and fast. The net result of this stage is that we are going to reboot the printer into a custom-compiled kernel. The process of doing so is rather unusual; because we can't convince the first-stage bootloader on the system to do our bidding (the kernel is signed from that perspective), we need to hot-reboot. We perform the following steps in order to do this.
Setting up the overlays in the initramfs. Once the new kernel boots, the first userspace code that executes is an initramfs, with init being a shellscript that lives, oddly enough, in initramfs/init. We start off by painting a cute logo, and setting a larger font on screen. Then, roughly, we:
At the moment that init gets control, the filesystem looks like this:
/ # Combined root filesystem, including all layers. /mnt/sdcard # SD card mount moved to be a subtree of the new root. /mnt/rootfs # Access to the "real" root filesystem, so that kernel drivers can see it if needed. /mnt/overlay # tmpfs containing individual overlay layers, including: /mnt/overlay/00.00.28.55.squashfs # Repacked Bambu base filesystem /mnt/overlay/1.0.squashfs # Precompiled X1Plus filesystem /mnt/overlay/bbl_screen-1.0.squashfs # Patched bbl_screen image
Booting the OS. OS boot is mostly unremarkable, but we do override some components of the base system. See images/cfw/etc/init.d/ for bits and pieces that we override.
Launching the patched GUI. Here is the other sort of "interesting and creative" bit of X1Plus: how we patch the GUI. Our general goal is that we wish to redistribute as little of Bambu Lab's IP as possible, and instead, only redistribute our own modifications to it. The mechanics of this is all handled by bbl_screen-patch/, which ultimately spits out a printer_ui.so that gets LD_PRELOADed into bbl_screen. Here is the rough process from start to finish of how that happens; most of it happens at build time:
At last, you have a beautiful X1Plus splash screen!
This probably could use a fair bit more discussion, but in short, you should be able to just make. I would describe it better, but it is really quite embarrassing. The Electron installer app really is not integrated into the build system yet, and if you intend to hack on that, you should probably ask about it if you cannot decipher it already.
One thing to think about is that, by default, bbl_screen-patch/Makefile will overwrite the printer_ui directory if it believes that the patches directory has changed. This is great if you are just building from git, but if you are actually trying to make changes to the printer_ui, this is rather surprising behavior. To avoid this, you can put NO_AUTO_PATCH=yes in your localconfig.mk.
You almost certainly want to build in Docker.
For better or for worse, we do most of our development discussion in Discord. Because of how much of a pain it is to merge printer_ui patches, please let other people know what you're working on!
We work with pull requests and bug reports on GitHub. Please reserve bug reports for actually triaged -- or, if not triaged, triageable -- bugs; if you have usage questions, please talk about those in "Discussions"!
Please be reasonable human beings to each other. It is just a 3D printer. If you have a problem, please chat with some of the maintainers and we will try to help you resolve it.
X1Plus was written by a small number of people, not all of whom wish to be publicly identified. You might see a handful names around the code from people who don't mind sharing their identity, but there were many more people behind the scenes who have contributed over time!
This probably ought go into a wiki page, but, you know, here we are.
As of writing, it's not necessary to build a kernel image yourself as there's one present in prebuilt. But you can! This might be desirable to enable other kernel features for development, or to build a kernel module against.
export LDFLAGS="-L$TOOLCHAIN/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf \ -Larm-linux-gnueabihf/libc/usr/lib/ -L/usr/arm-linux-gnueabihf/lib/" export CCFLAGS="-I$TOOLCHAIN/include -I/usr/include"
| Back | FazBrowse Home | New Git URL |