Confirm the print path on a real P1P, and stop discarding its answer
Print control (pause/resume/stop) and print start are now both confirmed
against the P1P on the LAN, and doing that turned up three real defects.
`start_uploaded_file` published fire-and-forget, so the printer's reply was
thrown away. Asking it to print a file it does not have returned `Ok(())`,
and watching `print.push_status` could not tell that apart from a successful
start, since both leave the machine IDLE for a while. The printer does in
fact answer - `{"command":"gcode_file","param":"...","reason":"error
string","result":"fail"}` - and it echoes the `sequence_id` we send, so
`request` correlates it. Both this and `control_print` now go out as
correlated requests and run the reply through `print_command_outcome`.
The upload and the print command disagreed about where files live. `upload`
cwd'd into `cache/` while the printable projects are in the card's root: the
root holds 43 `<name>.gcode.3mf` archives, `cache/` holds the printer's own
extracted `<project>_plate_N.gcode` working copies with `.gcode.bbl`
sidecars. Those extracted copies are not independently printable -
`gcode_file` with `param: "/cache/Cube_plate_1.gcode"` was rejected for a
file the FTPS listing shows is right there - while `project_file` with
`url: "ftp:///Cube.gcode.3mf"` started a print. So the destination is now a
parameter and both halves point at `SD_ROOT`.
What the hardware settled, recorded in the doc comments: the `ftp:///` url
spelling is right, `param: "Metadata/plate_1.gcode"` works for a
single-plate project, `use_ams: false` + `ams_mapping: ""` is accepted, and
a stop during PREPARE/RUNNING moves the printer to FAILED, which is how
Bambu reports an operator cancellation. What it did not settle: all three
control verbs answer `result: "success"` on an *idle* printer, so the reply
means "accepted", not "the state changed" - callers still have to read
`gcode_state` back.
`PrinterCommand::ControlPrint` makes this reachable from the cloud at all;
until now pause/resume/stop existed in the proxy with no way to send them.
Still no start-print variant, now for a different reason: the path around it
is missing, not the hardware proof.
Also: `list_dir` for any directory (how the layout above was found, without
sending a print command to guess), `request_raw` for probing an unconfirmed
command shape, and two examples - `bambu_cache_list` (read-only) and
`bambu_print_probe` (gated steps, `start` needing both IDLE and
--yes-start-a-real-print).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,26 @@ const FTPS_USER: &str = "bblp";
|
||||
/// print something that already lives here.
|
||||
pub const CACHE_DIR: &str = "cache";
|
||||
|
||||
/// The SD card's root, which is where an FTPS login lands and - confirmed
|
||||
/// live on a P1P, 2026-10-11 - the only directory a `print.project_file`
|
||||
/// command has been seen to print from.
|
||||
///
|
||||
/// The card's two interesting directories hold different things, and a
|
||||
/// listing of the real P1P is the clearest way to say which:
|
||||
///
|
||||
/// - the root holds 43 `<name>.gcode.3mf` files, the printable project
|
||||
/// archives Bambu Studio sends when it uploads a plate;
|
||||
/// - `cache/` holds 20 `<project>_plate_N.gcode` files with
|
||||
/// `<N>_<project>.gcode.bbl` sidecars - the printer's own extracted
|
||||
/// per-plate working copies.
|
||||
///
|
||||
/// Those extracted copies look like the obvious thing to print and are not:
|
||||
/// `print.gcode_file` with `param: "/cache/Cube_plate_1.gcode"` was
|
||||
/// rejected (`result: "fail"`) for a file that demonstrably exists, while
|
||||
/// `print.project_file` with `url: "ftp:///Cube.gcode.3mf"` against the
|
||||
/// root started a print. So uploads go here, not into `cache/`.
|
||||
pub const SD_ROOT: &str = "/";
|
||||
|
||||
/// Blocking: opens an implicit-FTPS session to `host`, logs in with
|
||||
/// `access_code`, and writes `data` to `cache/{file_name}`. Returns however
|
||||
/// many bytes the server reported accepting.
|
||||
@@ -58,6 +78,7 @@ pub fn upload(
|
||||
host: &str,
|
||||
access_code: &str,
|
||||
connector: native_tls::TlsConnector,
|
||||
dir: &str,
|
||||
file_name: &str,
|
||||
data: &[u8],
|
||||
) -> anyhow::Result<u64> {
|
||||
@@ -73,7 +94,12 @@ pub fn upload(
|
||||
// either way, letting the server treat the stream as text is free
|
||||
// corruption.
|
||||
ftp.transfer_type(FileType::Binary)?;
|
||||
ftp.cwd(CACHE_DIR)?;
|
||||
// `SD_ROOT` means "don't change directory at all" - the FTPS login
|
||||
// already lands in the card's root, and `cwd("/")` is a needless round
|
||||
// trip that some servers answer less predictably than no request.
|
||||
if dir != SD_ROOT {
|
||||
ftp.cwd(dir)?;
|
||||
}
|
||||
|
||||
// `put_file` wants something that implements `Read`. `data` is already
|
||||
// bytes in memory (see `GenericPrinter::upload_project_file`'s doc
|
||||
@@ -89,3 +115,39 @@ pub fn upload(
|
||||
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
/// Blocking: lists `cache/` on the printer.
|
||||
///
|
||||
/// Read-only, and the counterpart to `upload`. The previous version of this
|
||||
/// comment said a `project_file` command "can only print something that is
|
||||
/// already in this directory", which is wrong twice over: the printable
|
||||
/// projects are in the root (see `SD_ROOT`), and this directory's contents
|
||||
/// were rejected when asked for directly. It is still how you find a real
|
||||
/// slicer-produced `.3mf`
|
||||
/// to test against, instead of hand-building one and then not knowing
|
||||
/// whether a failure was the command or the file.
|
||||
///
|
||||
/// Returns the server's raw LIST lines rather than parsed entries: Bambu's
|
||||
/// FTPS server formats them in the usual unix style, but the parsing is the
|
||||
/// caller's problem until something needs more than the file names.
|
||||
pub fn list(
|
||||
host: &str,
|
||||
access_code: &str,
|
||||
connector: native_tls::TlsConnector,
|
||||
dir: &str,
|
||||
) -> anyhow::Result<Vec<String>> {
|
||||
let mut ftp = NativeTlsFtpStream::connect_secure_implicit(
|
||||
(host, FTPS_PORT),
|
||||
NativeTlsConnector::from(connector),
|
||||
host,
|
||||
)?;
|
||||
|
||||
ftp.login(FTPS_USER, access_code)?;
|
||||
ftp.transfer_type(FileType::Binary)?;
|
||||
|
||||
let entries = ftp.list(Some(dir))?;
|
||||
|
||||
let _ = ftp.quit();
|
||||
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user