[{"data":1,"prerenderedAt":505},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fsdks\u002Frust":3},{"id":4,"title":5,"body":6,"description":498,"extension":499,"meta":500,"navigation":69,"path":501,"seo":502,"stem":503,"__hash__":504},"content\u002Fdocs\u002Fsdks\u002Frust.md","Rust SDK",{"type":7,"value":8,"toc":489},"minimark",[9,13,30,35,88,92,179,183,194,263,279,283,290,319,341,345,401,418,422,433,470,474,485],[10,11,5],"h1",{"id":12},"rust-sdk",[14,15,16,17,21,22,25,26,29],"p",{},"The Rust SDK is the source of truth for the protocol. The ",[18,19,20],"code",{},"conduyt"," crate has a ",[18,23,24],{},"no_std"," core (wire\u002FCOBS\u002FCRC8) for embedded use and an opt-in ",[18,27,28],{},"std"," feature that adds the full host-side device client with transports and module wrappers.",[31,32,34],"h2",{"id":33},"install","Install",[36,37,42],"pre",{"className":38,"code":39,"language":40,"meta":41,"style":41},"language-toml shiki shiki-themes github-light github-dark","# Cargo.toml — host client (default)\n[dependencies]\nconduyt = { version = \"1\", features = [\"std\"] }\n\n# Cargo.toml — no_std embedded\n[dependencies]\nconduyt = { version = \"1\", default-features = false }\n","toml","",[18,43,44,52,58,64,71,77,82],{"__ignoreMap":41},[45,46,49],"span",{"class":47,"line":48},"line",1,[45,50,51],{},"# Cargo.toml — host client (default)\n",[45,53,55],{"class":47,"line":54},2,[45,56,57],{},"[dependencies]\n",[45,59,61],{"class":47,"line":60},3,[45,62,63],{},"conduyt = { version = \"1\", features = [\"std\"] }\n",[45,65,67],{"class":47,"line":66},4,[45,68,70],{"emptyLinePlaceholder":69},true,"\n",[45,72,74],{"class":47,"line":73},5,[45,75,76],{},"# Cargo.toml — no_std embedded\n",[45,78,80],{"class":47,"line":79},6,[45,81,57],{},[45,83,85],{"class":47,"line":84},7,[45,86,87],{},"conduyt = { version = \"1\", default-features = false }\n",[31,89,91],{"id":90},"quick-start-host","Quick start (host)",[36,93,97],{"className":94,"code":95,"language":96,"meta":41,"style":41},"language-rust shiki shiki-themes github-light github-dark","use conduyt::device::Device;\nuse conduyt::transports::serial::SerialTransport;\n\nfn main() -> Result\u003C(), Box\u003Cdyn std::error::Error>> {\n    let transport = SerialTransport::open(\"\u002Fdev\u002Fcu.usbmodem14101\", 115200)?;\n    let mut device = Device::new(transport);\n\n    let hello = device.connect()?;\n    println!(\"connected — {} bytes of HELLO_RESP\", hello.len());\n\n    device.pin_mode(13, conduyt::PIN_MODE_OUTPUT)?;\n    device.pin_write(13, 1)?;\n    device.close()?;\n    Ok(())\n}\n","rust",[18,98,99,104,109,113,118,123,128,132,138,144,149,155,161,167,173],{"__ignoreMap":41},[45,100,101],{"class":47,"line":48},[45,102,103],{},"use conduyt::device::Device;\n",[45,105,106],{"class":47,"line":54},[45,107,108],{},"use conduyt::transports::serial::SerialTransport;\n",[45,110,111],{"class":47,"line":60},[45,112,70],{"emptyLinePlaceholder":69},[45,114,115],{"class":47,"line":66},[45,116,117],{},"fn main() -> Result\u003C(), Box\u003Cdyn std::error::Error>> {\n",[45,119,120],{"class":47,"line":73},[45,121,122],{},"    let transport = SerialTransport::open(\"\u002Fdev\u002Fcu.usbmodem14101\", 115200)?;\n",[45,124,125],{"class":47,"line":79},[45,126,127],{},"    let mut device = Device::new(transport);\n",[45,129,130],{"class":47,"line":84},[45,131,70],{"emptyLinePlaceholder":69},[45,133,135],{"class":47,"line":134},8,[45,136,137],{},"    let hello = device.connect()?;\n",[45,139,141],{"class":47,"line":140},9,[45,142,143],{},"    println!(\"connected — {} bytes of HELLO_RESP\", hello.len());\n",[45,145,147],{"class":47,"line":146},10,[45,148,70],{"emptyLinePlaceholder":69},[45,150,152],{"class":47,"line":151},11,[45,153,154],{},"    device.pin_mode(13, conduyt::PIN_MODE_OUTPUT)?;\n",[45,156,158],{"class":47,"line":157},12,[45,159,160],{},"    device.pin_write(13, 1)?;\n",[45,162,164],{"class":47,"line":163},13,[45,165,166],{},"    device.close()?;\n",[45,168,170],{"class":47,"line":169},14,[45,171,172],{},"    Ok(())\n",[45,174,176],{"class":47,"line":175},15,[45,177,178],{},"}\n",[31,180,182],{"id":181},"modules","Modules",[14,184,185,186,189,190,193],{},"Module wrappers live under ",[18,187,188],{},"conduyt::modules",". They borrow ",[18,191,192],{},"&mut Device\u003CT>"," so you can keep using the device after a module call returns:",[36,195,197],{"className":94,"code":196,"language":96,"meta":41,"style":41},"use conduyt::modules::{\n    servo::Servo,\n    neopixel::NeoPixel,\n    oled::OLED,\n    dht::DHT,\n    encoder::Encoder,\n    stepper::Stepper,\n    pid::PID,\n};\n\nlet mut servo = Servo::new(&mut device, 0);   \u002F\u002F module_id = 0\nservo.attach(9, 1000, 2000)?;\nservo.write(90)?;\n",[18,198,199,204,209,214,219,224,229,234,239,244,248,253,258],{"__ignoreMap":41},[45,200,201],{"class":47,"line":48},[45,202,203],{},"use conduyt::modules::{\n",[45,205,206],{"class":47,"line":54},[45,207,208],{},"    servo::Servo,\n",[45,210,211],{"class":47,"line":60},[45,212,213],{},"    neopixel::NeoPixel,\n",[45,215,216],{"class":47,"line":66},[45,217,218],{},"    oled::OLED,\n",[45,220,221],{"class":47,"line":73},[45,222,223],{},"    dht::DHT,\n",[45,225,226],{"class":47,"line":79},[45,227,228],{},"    encoder::Encoder,\n",[45,230,231],{"class":47,"line":84},[45,232,233],{},"    stepper::Stepper,\n",[45,235,236],{"class":47,"line":134},[45,237,238],{},"    pid::PID,\n",[45,240,241],{"class":47,"line":140},[45,242,243],{},"};\n",[45,245,246],{"class":47,"line":146},[45,247,70],{"emptyLinePlaceholder":69},[45,249,250],{"class":47,"line":151},[45,251,252],{},"let mut servo = Servo::new(&mut device, 0);   \u002F\u002F module_id = 0\n",[45,254,255],{"class":47,"line":157},[45,256,257],{},"servo.attach(9, 1000, 2000)?;\n",[45,259,260],{"class":47,"line":163},[45,261,262],{},"servo.write(90)?;\n",[14,264,265,266,269,270,273,274,278],{},"Each wrapper takes the device and a ",[18,267,268],{},"module_id"," byte. Get the ID from the parsed ",[18,271,272],{},"HELLO_RESP"," (or hard-code if you control the firmware). See the per-module pages under ",[275,276,182],"a",{"href":277},"\u002Fdocs\u002Fmodules\u002Fservo"," for command references.",[31,280,282],{"id":281},"no_std-core","no_std core",[14,284,285,286,289],{},"If you're writing an embedded host (or even another firmware that talks CONDUYT), use the core with ",[18,287,288],{},"default-features = false",":",[36,291,293],{"className":94,"code":292,"language":96,"meta":41,"style":41},"use conduyt::wire::{wire_encode, wire_decode, make_packet};\n\nlet pkt = make_packet(0x01 \u002F* CMD_PING *\u002F, 0, &[]);\nlet mut buf = [0u8; 32];\nlet n = wire_encode_into(&pkt, &mut buf);    \u002F\u002F no allocation\n",[18,294,295,300,304,309,314],{"__ignoreMap":41},[45,296,297],{"class":47,"line":48},[45,298,299],{},"use conduyt::wire::{wire_encode, wire_decode, make_packet};\n",[45,301,302],{"class":47,"line":54},[45,303,70],{"emptyLinePlaceholder":69},[45,305,306],{"class":47,"line":60},[45,307,308],{},"let pkt = make_packet(0x01 \u002F* CMD_PING *\u002F, 0, &[]);\n",[45,310,311],{"class":47,"line":66},[45,312,313],{},"let mut buf = [0u8; 32];\n",[45,315,316],{"class":47,"line":73},[45,317,318],{},"let n = wire_encode_into(&pkt, &mut buf);    \u002F\u002F no allocation\n",[14,320,321,322,325,326,329,330,332,333,336,337,340],{},"The no_std build pulls in ",[18,323,324],{},"alloc"," for ",[18,327,328],{},"Vec"," but no ",[18,331,28],{},". Suitable for ",[18,334,335],{},"#[no_std]"," Rust embedded targets (RP2040, ESP32-via-",[18,338,339],{},"esp-rs",", nRF52, STM32).",[31,342,344],{"id":343},"transports","Transports",[346,347,348,364],"table",{},[349,350,351],"thead",{},[352,353,354,358,361],"tr",{},[355,356,357],"th",{},"Transport",[355,359,360],{},"Module",[355,362,363],{},"Feature flag",[365,366,367,387],"tbody",{},[352,368,369,373,378],{},[370,371,372],"td",{},"Serial",[370,374,375],{},[18,376,377],{},"conduyt::transports::serial::SerialTransport",[370,379,380,382,383,386],{},[18,381,28],{}," (uses ",[18,384,385],{},"serialport"," crate)",[352,388,389,392,397],{},[370,390,391],{},"Mock",[370,393,394],{},[18,395,396],{},"conduyt::transports::MockTransport",[370,398,399],{},[18,400,28],{},[14,402,403,404,406,407,410,411,410,414,417],{},"For embedded transports, implement the ",[18,405,357],{}," trait yourself — it's three methods (",[18,408,409],{},"connect",", ",[18,412,413],{},"send",[18,415,416],{},"recv",") and an associated error type.",[31,419,421],{"id":420},"errors","Errors",[14,423,424,425,428,429,432],{},"Every device method returns ",[18,426,427],{},"Result\u003CT, DeviceError\u003CT::Error>>",". ",[18,430,431],{},"DeviceError"," distinguishes:",[434,435,436,443,449,455,461],"ul",{},[437,438,439,442],"li",{},[18,440,441],{},"Transport(_)"," — your transport returned an error",[437,444,445,448],{},[18,446,447],{},"Nak { code, name, seq }"," — firmware returned NAK with a known error code",[437,450,451,454],{},[18,452,453],{},"Timeout { seq }"," — no response within the configured window",[437,456,457,460],{},[18,458,459],{},"WireError(_)"," — bad magic, CRC mismatch, version mismatch, etc.",[437,462,463,466,467],{},[18,464,465],{},"NotConnected"," — you called a method before ",[18,468,469],{},"connect()",[31,471,473],{"id":472},"versioning","Versioning",[14,475,476,477,480,481,484],{},"The crate uses semver. ",[18,478,479],{},"1.x"," requires firmware running protocol version 2 — exposed as ",[18,482,483],{},"conduyt::PROTOCOL_VERSION",".",[486,487,488],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":41,"searchDepth":54,"depth":54,"links":490},[491,492,493,494,495,496,497],{"id":33,"depth":54,"text":34},{"id":90,"depth":54,"text":91},{"id":181,"depth":54,"text":182},{"id":281,"depth":54,"text":282},{"id":343,"depth":54,"text":344},{"id":420,"depth":54,"text":421},{"id":472,"depth":54,"text":473},"no_std-compatible Rust core + std device API — embedded firmware and host clients from the same crate.","md",{},"\u002Fdocs\u002Fsdks\u002Frust",{"title":5,"description":498},"docs\u002Fsdks\u002Frust","EPe8SIfeXw8r_CPLqi9aBjFfEr4zbC345wEyrn2eKqc",1777412315746]