| Crates.io | siyi-protocol |
| lib.rs | siyi-protocol |
| version | 0.1.0 |
| created_at | 2025-10-21 20:05:39.8394+00 |
| updated_at | 2025-10-21 20:05:39.8394+00 |
| description | SIYI Gimbal and Camera SDK Protocol |
| homepage | https://github.com/AhmedBoin/siyi-protocol |
| repository | https://github.com/AhmedBoin/siyi-protocol |
| max_upload_size | |
| id | 1894366 |
| size | 3,264,986 |
A type-safe, no_std compatible Rust implementation of the SIYI Gimbal Camera SDK protocol. This crate provides message definitions and serialization/deserialization for communicating with SIYI camera systems over TCP, UDP, or serial (TTL) connections.
no_std environments without allocAdd this to your Cargo.toml:
[dependencies]
siyi-protocol = "0.1"
Use feature flags to include only the messages your hardware supports. This significantly reduces code size and compilation time.
[dependencies]
siyi-protocol = { version = "0.1", features = ["zt30", "tcp"] }
For multiple protocols or cameras:
[dependencies]
siyi-protocol = { version = "0.1", features = ["zr10", "tcp", "udp"] }
To include everything (not recommended for embedded):
[dependencies]
siyi-protocol = { version = "0.1", features = ["all"] }
use siyi_protocol::zt30_tcp::*;
fn main() {
// Create a request for firmware version
let request = FirmwareVersionRequest::new();
// Encode the message to a buffer
let mut msg_buf = [0u8; MAX_MESSAGE_SIZE];
let msg_len = request.encode(&mut msg_buf).unwrap();
// Create a frame with the encoded message
let mut frame_buf = [0u8; MAX_FRAME_SIZE];
let frame = request.to_frame(&msg_buf[..msg_len]);
let frame_len = frame.encode(&mut frame_buf).unwrap();
// Send frame_buf[..frame_len] over your transport
// socket.send(&frame_buf[..frame_len])?;
}
use siyi_protocol::zt30_tcp::*;
fn main() {
// Receive data from your transport
let mut recv_buf = [0u8; MAX_FRAME_SIZE];
// let recv_len = socket.recv(&mut recv_buf)?;
// Decode the frame
let frame = Frame::decode(&recv_buf[..recv_len]).unwrap();
// Decode the message from the frame
let message = Message::from_frame(&frame).unwrap();
// Handle the message
match message {
Message::FirmwareVersionResponse(resp) => {
println!("Camera FW: {}", resp.camera_firmware_ver);
println!("Gimbal FW: {}", resp.gimbal_firmware_ver);
}
Message::GimbalAttitudeResponse(resp) => {
println!("Yaw: {:.1}°", resp.yaw as f32 / 10.0);
println!("Pitch: {:.1}°", resp.pitch as f32 / 10.0);
}
_ => println!("Other message received"),
}
}
The SIYI protocol uses a binary frame format:
┌─────────┬──────┬─────────┬─────┬────────┬──────┬────────┐
│ STX │ CTRL │ DATALEN │ SEQ │ CMD_ID │ DATA │ CRC16 │
│ 2 bytes │ 1 │ 2 │ 2 │ 1 │ N │ 2 │
└─────────┴──────┴─────────┴─────┴────────┴──────┴────────┘
All multi-byte fields use little-endian byte order.
FirmwareVersionRequest/Response - Get firmware versionsHardwareIdRequest/Response - Get device hardware IDAutoFocusRequest/Response - Trigger autofocusManualZoomRequest/Response - Control zoom levelAbsoluteZoomRequest/Response - Set specific zoom levelGimbalRotationRequest/Response - Control gimbal movementGimbalAttitudeRequest/Response - Get current anglesSetGimbalAttitudeRequest/Response - Set target anglesCenterGimbalRequest/Response - Reset to center positionGimbalModeRequest/Response - Get/set gimbal modeFunctionControl - Take photo, start/stop recordingFunctionFeedback - Camera feedback eventsCameraSystemInfoRequest/Response - Get system statusGetTemperatureAtPointRequest/Response - Point temperatureLocalTemperatureMeasurementRequest/Response - Area temperatureGlobalTemperatureMeasurementRequest/Response - Full framePseudoColorRequest/Response - Get/set thermal paletteThermalGainModeRequest/Response - Configure gain modeLaserDistanceRequest/Response - Get range measurementLaserTargetLocationRequest/Response - Get target GPS coordinatesSetLaserStateRequest/Response - Enable/disable laserEncodingParamsRequest/Response - Get encoding settingsSetEncodingParamsRequest/Response - Configure video encodingVideoStitchingModeRequest/Response - Multi-sensor stitchingAiModeStatusRequest/Response - Check AI module statusAiTrackingCoordinateStream - Real-time tracking dataSetAiTrackingStreamStatusRequest/Response - Control tracking outputThe crate uses fixed-size buffers with compile-time known sizes. No heap allocation is required.
All buffers are stack-allocated. The exact size depends on which messages you include via feature flags.
This crate provides only message definitions and serialization. You need to implement your own transport layer:
use std::net::TcpStream;
use std::io::{Read, Write};
use siyi_protocol::zt30_tcp::*;
let mut stream = TcpStream::connect("192.168.144.25:37260")?;
// Send request
let request = GimbalAttitudeRequest::new();
let mut msg_buf = [0u8; MAX_MESSAGE_SIZE];
let mut frame_buf = [0u8; MAX_FRAME_SIZE];
let msg_len = request.encode(&mut msg_buf)?;
let frame = request.to_frame(&msg_buf[..msg_len]);
let frame_len = frame.encode(&mut frame_buf)?;
stream.write_all(&frame_buf[..frame_len])?;
// Receive response
let mut recv_buf = [0u8; MAX_FRAME_SIZE];
let recv_len = stream.read(&mut recv_buf)?;
let frame = Frame::decode(&recv_buf[..recv_len])?;
let message = Message::from_frame(&frame)?;
use serialport::SerialPort;
use siyi_protocol::zr10_ttl::*;
let mut port = serialport::new("/dev/ttyUSB0", 115200)
.timeout(Duration::from_millis(100))
.open()?;
// Send and receive similar to TCP example
The crate provides two error types:
pub enum EncodeError {
BufferTooSmall,
}
pub enum DecodeError {
FrameTooShort,
InvalidStx,
FrameIncomplete,
CrcMismatch,
NotEnoughBytes,
InvalidEnumValue,
ConversionError,
UnknownCmdId,
}
Both implement Debug, Clone, Copy, PartialEq, and Eq for easy error handling.
This crate is generated from an XML protocol definition using a Python script. The XML format allows:
To regenerate the code after modifying the XML:
./generate_all.sh
This creates optimized modules for each camera/protocol combination.
tcp - Enable TCP protocol messagesudp - Enable UDP protocol messagesttl - Enable serial (TTL) protocol messageszt30 - SIYI ZT30 camera supportzt6 - SIYI ZT6 camera supportzr30 - SIYI ZR30 camera supportzr10 - SIYI ZR10 camera supporta8mini - SIYI A8mini camera supporta2mini - SIYI A2mini camera supportall - Enable all protocols and cameras (large binary size)See the examples/ directory:
serialize_messages.rs - Demonstrates message encodingdeserialize_messages.rs - Demonstrates message decodingRun examples with:
cargo run --example serialize_messages --features "zt30,tcp"
cargo run --example deserialize_messages --features "zt30,tcp"
This project is licensed under the MIT License - see the LICENSE file for details.
Protocol specification based on the SIYI Gimbal Camera External SDK Protocol documentation.
Contributions are welcome! Please ensure:
./generate_all.sh after XML modificationsFor protocol questions, refer to the official SIYI SDK documentation. For issues with this crate, please file an issue on the repository.