System commands
brick.system() has one method per system command, the protocol
commands for files, firmware modules, settings and firmware updates
(Bluetooth Developer Kit, appendix 1).
Commands
| Opcode | Method | Reply |
|---|---|---|
0x80 | open_read(&name) | OpenedFile { handle, size } |
0x81 | open_write(&name, size) | FileHandle |
0x82 | read(handle, len) | Chunk (≤ 58 bytes) |
0x83 | write(handle, data) | u16 bytes written (≤ 61 per call) |
0x84 | close(handle) | () |
0x85 | delete(&name) | () |
0x86 | find_first(&pattern) | FoundFile { handle, name, size } |
0x87 | find_next(handle) | FoundFile |
0x88 | get_firmware_version() | FirmwareVersion |
0x89 | open_write_linear(&name, size) | FileHandle |
0x8A | open_read_linear(&name) | u32 flash address |
0x8B | open_write_data(&name, size) | FileHandle |
0x8C | open_append_data(&name) | OpenedFile (size = space left) |
0x90 | boot() | (), USB only |
0x91 | set_brick_name(&name) | () |
0x94 | get_device_info() | DeviceInfo |
0x97 | delete_user_flash() | (): deletes all files |
0x98 | poll_command_length(buffer) | u8 |
0x99 | poll(buffer, len) | Chunk |
0x9A | bluetooth_factory_reset() | (), USB only |
0xA0 | request_first_module(&pattern) | ModuleInfo |
0xA1 | request_next_module(handle) | ModuleInfo |
0xA2 | close_module_handle(handle) | () |
0xA3 | read_io_map(module, offset, len) | Chunk (≤ 55 bytes) |
0xA4 | write_io_map(module, offset, data) | u16 (≤ 54 bytes per call) |
| — | read_io_map_all(module, offset, len) | Vec<u8>, as many requests as needed |
| — | write_io_map_all(module, offset, data) | (), as many requests as needed |
Files with raw handles
Unlike the high-level API, nothing is closed for you here. Every handle you open, you close:
nxt_rs::doc_example(|brick| async move {
use nxt_rs::protocol::FileName;
let s = brick.system();
let name = FileName::new("raw.txt")?;
let h = s.open_write(&name, 5).await?;
s.write(h, b"hello").await?;
s.close(h).await?;
let file = s.open_read(&name).await?;
let data = s.read(file.handle, 5).await?;
s.close(file.handle).await?;
assert_eq!(&*data, b"hello");
Ok(()) });
A search handle from find_first must also be closed, unless the search
ended with Status::NoMoreFiles.
In Drop implementations, which can’t .await, use
brick.close_file_later(handle) or brick.close_module_later(handle). The
close is then sent just before the next command. The high-level file types
work this way.
Firmware modules and I/O maps
The firmware is made of modules (Display.mod, Output.mod, …). Each one
exposes an I/O map, a block of memory you can read and write. That gives
access to internals no command covers.
nxt_rs::doc_example(|brick| async move {
use nxt_rs::protocol::{FileName, ModuleId};
let s = brick.system();
let mut module = s.request_first_module(&FileName::new("*.*")?).await?;
loop {
println!("{:<14} id {:#010x}, I/O map {} bytes", module.name, module.id.0, module.io_map_size);
match s.request_next_module(module.handle).await {
Ok(next) => module = next,
Err(_) => break,
}
}
s.close_module_handle(module.handle).await?;
// The screen buffer: 800 bytes at offset 119 of the display module.
let screen = s.read_io_map_all(ModuleId::DISPLAY, 119, 800).await?;
Ok(()) });
ModuleId has constants for the modules of LEGO’s standard firmware. Look
the IDs up with request_first_module if you run a different firmware.
USB-only commands
boot (reboot into the SAM-BA firmware-update mode) and
bluetooth_factory_reset are only accepted over USB. They only exist on a
brick whose transport supports them:
async fn f(brick: nxt_rs::Brick<nxt_rs::transport::AnyTransport>) -> nxt_rs::Result<()> {
brick.system().bluetooth_factory_reset().await?; // error: not available over AnyTransport
Ok(()) }
Brick<Usb>::boot_sam_ba(self) consumes the brick, because the connection
is gone afterwards.
Warning: after
boot, the brick ticks and does nothing until new firmware is flashed with a tool such as LEGO’s firmware updater orlibnxt. Don’t call it by accident.