Windows Error 87 when raising DTR line (serial) - windows

I am attempting to communicate with a serial device over a TTL->RS-232 converter. This converter requires power be sent on the DTR and RTS lines.
// imports
extern crate serial; //see: https://dcuddeback.github.io/serial-rs/serial/index.html
use std::env;
use std::io;
use std::time::Duration;
use std::process::exit;
use std::io::prelude::*;
use serial::prelude::*;
use serial::{BaudRate, CharSize, Parity, StopBits, FlowControl, SystemPort, PortSettings, Error};
use std::mem;
#[inline]
fn display_error_message(err: &Error, msg: &str) -> ! {
println!("{}", msg);
println!("Error Code: {:?}", err.raw_os_error());
println!("Error: {:?}", err);
exit(0);
}
fn main() {
// open port
let mut port = match serial::open("COM3") {
Err(ref e) => display_error_message(e, "Error opening serial port"),
Ok(x) => x,
};
// push settings to stack
let settings = PortSettings {
baud_rate: BaudRate::Baud115200,
char_size: CharSize::Bits8,
parity: Parity::ParityNone,
stop_bits: StopBits::Stop1,
flow_control: FlowControl::FlowNone,
};
// configure port
match port.configure(&settings) {
Ok(_) => {}
Err(ref e) => display_error_message(e, "Error configuring serial port."),
};
// set rts
match port.set_rts(true) {
Ok(_) => {}
Err(ref e) => display_error_message(e, "Error setting RTS line"),
};
// set DTR
match port.set_dtr(true) {
Ok(_) => {}
Err(ref e) => display_error_message(e, "Error setting DTR line"),
};
// allocate readbuffer on stack
let mut rb: [u8; 1] = [0u8; 1];
// allocate buffer to hold output
let mut out: String = String::with_capacity(1024);
// loop while reading
loop {
match port.read(&mut rb) {
Ok(_) => {}
Err(ref e) => {
println!("Error reading serial port.");
println!("Error: {:?}", e);
exit(0);
}
};
match rb[0] {
// Linefeed
10 => {
println!("{}<LF>", &out);
out = String::with_capacity(1024);
}
// carriage return
13 => {
println!("{}<CR>", &out);
out = String::with_capacity(1024);
}
// normal chars
32...126 => {
let temp: u32 = rb[0].clone() as u32;
let ch: char = unsafe { mem::transmute(temp) };
out.push(ch);
}
// everything else
x => {
println!("Non standard character encountered");
println!("Value: {:?}", x);
exit(0);
}
};
}
}
The source code is also on the Rust Playground and Github.
I am using the serial-rs library and Rust 1.8 (GNU ABI Windows 7 x64 Professional).
My error occurs on line 46:
match port.set_dtr( true ) {
Ok(_) => { },
Err(ref e) => display_error_message(e,"Error setting DTR line")
};
This returns error code 87 (on Windows 7). The standard serial-rs doesn't save the error code so I'm using my own fork (pending a PR).
This error is from a malformed system call. Diving into serial-rs one will see set_dtr(bool) is just wrapping a call to EscapeCommFunction(2) first call, second call, third call. The arguments codes appear correct.
Compiling with the MSVC toolchain results in same error, placing the DTR call before RTS call results in same error.
Raising DTR and RTS at the same time works in py-serial, but I can't write to the port while doing so. See other issue

The error resulted from the DTR line was not supported within the serial port emulation driver of the USB->RS232 converter.

Related

Adding writer function to tunnel program

How do I create a writer function for the tunnel program below? The code below is a sample program to create windows tunnel interface. I want to write a function that writes (or sends) packets to another server IP address. Github link for full code and its dependencies given below.
https://github.com/nulldotblack/wintun/blob/main/examples/basic.rs
use log::*;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
static RUNNING: AtomicBool = AtomicBool::new(true);
fn main() {
env_logger::init();
let wintun = unsafe { wintun::load_from_path("examples/wintun/bin/amd64/wintun.dll") }
.expect("Failed to load wintun dll");
let version = wintun::get_running_driver_version(&wintun);
info!("Using wintun version: {:?}", version);
let adapter = match wintun::Adapter::open(&wintun, "Demo") {
Ok(a) => a,
Err(_) => wintun::Adapter::create(&wintun, "Example", "Demo", None)
.expect("Failed to create wintun adapter!"),
};
let version = wintun::get_running_driver_version(&wintun).unwrap();
info!("Using wintun version: {:?}", version);
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
let reader_session = session.clone();
let reader = std::thread::spawn(move || {
while RUNNING.load(Ordering::Relaxed) {
match reader_session.receive_blocking() {
Ok(packet) => {
let bytes = packet.bytes();
println!(
"Read packet size {} bytes. Header data: {:?}",
bytes.len(),
&bytes[0..(20.min(bytes.len()))]
);
}
Err(_) => println!("Got error while reading packet"),
}
}
});
println!("Press enter to stop session");
let mut line = String::new();
let _ = std::io::stdin().read_line(&mut line);
println!("Shutting down session");
RUNNING.store(false, Ordering::Relaxed);
session.shutdown();
let _ = reader.join();
println!("Shutdown complete");
}

OpenGL gl::GetUniformLocation fails to locate uniform only in certain cases

I'm kinda stuck. I have a program abstraction to locate uniforms for me. I have a fragment shader with a float uniform elapsed, and a vertex shader with a mat4 uniform projection.
The helper function is defined as followed:
pub fn find_uniform(&mut self, name: &str) -> Result<(), UniformError> {
if let Some(_) = self.uniforms.get(name) {
return Ok(());
}
let target_location = unsafe {
let location = gl::GetUniformLocation(self.program_id, name.as_bytes().as_ptr() as *const i8);
let error = gl::GetError();
if error != gl::NO_ERROR {
return Err(UniformError::new(true, error));
}
location
};
if target_location < 0 {
return Err(UniformError::new(false, UNIFORM_NOT_FOUND));
}
self.uniforms.insert(name.to_string(), target_location);
return Ok(());
}
If I use the helper function to look for only elapsed or if i look for both with native gl calls it works:
// No error
if let Err(e) = program.find_uniform("elapsed") {
eprint!("Failed to find elapsed, probably loading wrong shader. err: {}", e);
return;
};
// OR
unsafe {
let location1 = gl::GetUniformLocation(program.program_id, b"elapsed".as_ptr() as *const i8);
println!("{}", location1); // 0
let location2 = gl::GetUniformLocation(program.program_id, b"projection".as_ptr() as *const i8);
println!("{}", location2); // 1
}
But if I use my helper function for both it fails to find whatever i look for first:
if let Err(e) = program.find_uniform("elapsed") {
// Enters error branch here
eprint!("Failed to find elapsed, probably loading wrong shader. err: {}", e);
return;
};
if let Err(e) = program.find_uniform("projection") {
eprint!("Failed to find projection, probably loading wrong shader. err: {}", e);
return;
};
Does anyone have an idea of what I'm doing wrong?
Looking at your code, the conversion to name.as_bytes().as_ptr() as *const i8 is unsafe and depends on memory layout. Rust strings are not C-strings and are not null terminated by default. Use std::ffi::CString::new(); to ensure the string null-terminated. So your current program depends purely if you get lucky in having a null byte after your byte strings.
The following code should work:
let target_location = unsafe {
use std::ffi::CString;
let c_name = CString::new(name).expect("Convert to c-string");
let location = gl::GetUniformLocation(self.program_id, c_name.as_ptr());
let error = gl::GetError();
if error != gl::NO_ERROR {
return Err(UniformError::new(true, error));
}
location
};
See also:
How to pass data to openGL functions correctly in Rust

Select from a list of sockets using futures

I am trying out the yet-unstable async-await syntax in nightly Rust 1.38 with futures-preview = "0.3.0-alpha.16" and runtime = "0.3.0-alpha.6". It feels really cool, but the docs are (yet) scarce and I got stuck.
To go a bit beyond the basic examples I would like to create an app that:
Accepts TCP connections on a given port;
Broadcasts all the data received from any connection to all active connections.
Existing docs and examples got me this far:
#![feature(async_await)]
#![feature(async_closure)]
use futures::{
prelude::*,
select,
future::select_all,
io::{ReadHalf, WriteHalf, Read},
};
use runtime::net::{TcpListener, TcpStream};
use std::io;
async fn read_stream(mut reader: ReadHalf<TcpStream>) -> (ReadHalf<TcpStream>, io::Result<Box<[u8]>>) {
let mut buffer: Vec<u8> = vec![0; 1024];
match reader.read(&mut buffer).await {
Ok(len) => {
buffer.truncate(len);
(reader, Ok(buffer.into_boxed_slice()))
},
Err(err) => (reader, Err(err)),
}
}
#[runtime::main]
async fn main() -> std::io::Result<()> {
let mut listener = TcpListener::bind("127.0.0.1:8080")?;
println!("Listening on {}", listener.local_addr()?);
let mut incoming = listener.incoming().fuse();
let mut writers: Vec<WriteHalf<TcpStream>> = vec![];
let mut reads = vec![];
loop {
select! {
maybe_stream = incoming.select_next_some() => {
let (mut reader, writer) = maybe_stream?.split();
writers.push(writer);
reads.push(read_stream(reader).fuse());
},
maybe_read = select_all(reads.iter()) => {
match maybe_read {
(reader, Ok(data)) => {
for writer in writers {
writer.write_all(data).await.ok(); // Ignore errors here
}
reads.push(read_stream(reader).fuse());
},
(reader, Err(err)) => {
let reader_addr = reader.peer_addr().unwrap();
writers.retain(|writer| writer.peer_addr().unwrap() != reader_addr);
},
}
}
}
}
}
This fails with:
error: recursion limit reached while expanding the macro `$crate::dispatch`
--> src/main.rs:36:9
|
36 | / select! {
37 | | maybe_stream = incoming.select_next_some() => {
38 | | let (mut reader, writer) = maybe_stream?.split();
39 | | writers.push(writer);
... |
55 | | }
56 | | }
| |_________^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
This is very confusing. Maybe I am using select_all() in a wrong way? Any help in making it work is appreciated!
For completeness, my Cargo.toml:
[package]
name = "async-test"
version = "0.1.0"
authors = ["xxx"]
edition = "2018"
[dependencies]
runtime = "0.3.0-alpha.6"
futures-preview = { version = "=0.3.0-alpha.16", features = ["async-await", "nightly"] }
In case someone is following, I hacked it together finally. This code works:
#![feature(async_await)]
#![feature(async_closure)]
#![recursion_limit="128"]
use futures::{
prelude::*,
select,
stream,
io::ReadHalf,
channel::{
oneshot,
mpsc::{unbounded, UnboundedSender},
}
};
use runtime::net::{TcpListener, TcpStream};
use std::{
io,
net::SocketAddr,
collections::HashMap,
};
async fn read_stream(
addr: SocketAddr,
drop: oneshot::Receiver<()>,
mut reader: ReadHalf<TcpStream>,
sender: UnboundedSender<(SocketAddr, io::Result<Box<[u8]>>)>
) {
let mut drop = drop.fuse();
loop {
let mut buffer: Vec<u8> = vec![0; 1024];
select! {
result = reader.read(&mut buffer).fuse() => {
match result {
Ok(len) => {
buffer.truncate(len);
sender.unbounded_send((addr, Ok(buffer.into_boxed_slice())))
.expect("Channel error");
if len == 0 {
return;
}
},
Err(err) => {
sender.unbounded_send((addr, Err(err))).expect("Channel error");
return;
}
}
},
_ = drop => {
return;
},
}
}
}
enum Event {
Connection(io::Result<TcpStream>),
Message(SocketAddr, io::Result<Box<[u8]>>),
}
#[runtime::main]
async fn main() -> std::io::Result<()> {
let mut listener = TcpListener::bind("127.0.0.1:8080")?;
eprintln!("Listening on {}", listener.local_addr()?);
let mut writers = HashMap::new();
let (sender, receiver) = unbounded();
let connections = listener.incoming().map(|maybe_stream| Event::Connection(maybe_stream));
let messages = receiver.map(|(addr, maybe_message)| Event::Message(addr, maybe_message));
let mut events = stream::select(connections, messages);
loop {
match events.next().await {
Some(Event::Connection(Ok(stream))) => {
let addr = stream.peer_addr().unwrap();
eprintln!("New connection from {}", addr);
let (reader, writer) = stream.split();
let (drop_sender, drop_receiver) = oneshot::channel();
writers.insert(addr, (writer, drop_sender));
runtime::spawn(read_stream(addr, drop_receiver, reader, sender.clone()));
},
Some(Event::Message(addr, Ok(message))) => {
if message.len() == 0 {
eprintln!("Connection closed by client: {}", addr);
writers.remove(&addr);
continue;
}
eprintln!("Received {} bytes from {}", message.len(), addr);
if &*message == b"quit\n" {
eprintln!("Dropping client {}", addr);
writers.remove(&addr);
continue;
}
for (&other_addr, (writer, _)) in &mut writers {
if addr != other_addr {
writer.write_all(&message).await.ok(); // Ignore errors
}
}
},
Some(Event::Message(addr, Err(err))) => {
eprintln!("Error reading from {}: {}", addr, err);
writers.remove(&addr);
},
_ => panic!("Event error"),
}
}
}
I use a channel and spawn a reading task for each client. Special care had to be taken to ensure that readers get dropped with writers: this is why oneshot future is used. When oneshot::Sender is dropped, the oneshot::Receiver future resolves to canceled state, which is a notification mechanism for a reading task to know it is time to halt. To demonstrate that it works, we drop a client as soon as we get "quit" message.
Sadly, there is a (seemingly useless) warning regarding an unused JoinHandle from the runtime::spawn call, and I don't really know how to eliminate it.

Task 'rustc' has overflowed its stack

Chat server which fails to compile:
use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
enum StreamOrSlice {
Strm(TcpStream),
Slc(uint, [u8, ..1024])
}
fn main() {
let listener = TcpListener::bind("127.0.0.1", 5555);
// bind the listener to the specified address
let mut acceptor = listener.listen();
let (tx, rx) = channel();
spawn(proc() {
let mut streams: Vec<TcpStream> = Vec::new();
loop {
let rxd: StreamOrSlice = rx.recv();
match rxd {
Strm(stream) => {
streams.push(stream);
}
Slc(len, buf) => {
for stream in streams.iter_mut() {
let _ = stream.write(buf.slice(0, len));
}
}
}
}
});
// accept connections and process them, spawning a new tasks for each one
for stream in acceptor.incoming() {
match stream {
Err(e) => { /* connection failed */ }
Ok(mut stream) => {
// connection succeeded
tx.send(Strm(stream.clone()));
let tx2 = tx.clone();
spawn(proc() {
let mut buf: [u8, ..1024] = [0, ..1024];
loop {
let len = stream.read(buf);
tx2.send(Slc(len.unwrap(), buf));
}
})
}
}
}
}
The error is:
Compiling chat v0.1.0 (file:///home/chris/rust/chat)
task 'rustc' has overflowed its stack
Could not compile `chat`.
Is this fixable in code, or is it a compiler bug?
Note: #Levans thanks for your help this evening.
The compiler has crashed. You are not even writing your own macros. This is 100% a compiler bug. Report it.

Return an inline-defined enum from a function?

I'm diving into rust, and I'm trying to do something like this:
match send("select * from User;") {
ConnError => println!("Connection error!"),
DBError(e) => println!("Database error {}", e),
Ok(response) => {
...
}
}
and I'm trying to figure out a compact way of defining the send function. I saw the Result enum, but it only handles one kind of error at a time. I was hoping that I could define my own enum like this:
fn send(query: str) -> enum { Ok(Box<Response>), ConnError, DBError(str) } {
...
}
alas, it is not possible, it's complaining about the unexpected 'enum' keyword. Is there any way to do what I'm trying here, or perhaps make Result handle multiple error types? Thanks!
As you say, you can use Result but you have to define the enum with your error types separately, as you can't define it directly in the return of your function.
Something like this:
use std::rand::distributions::{IndependentSample, Range};
fn main() {
match send("select * from foo") {
Ok(Response) => println!("response"),
Err(e) => match e {
ConnError => println!("connection error"),
DbError(err) => println!("{}", err)
}
}
}
// the enum with your errors
enum DataLayerError {
ConnError,
DbError(String)
}
struct Response; /*...*/
fn send(_query: &str) -> Result<Response, DataLayerError> {
let between = Range::new(0u, 2);
let mut rng = std::rand::task_rng();
// return a random result
match between.ind_sample(&mut rng) {
0 => Ok(Response),
1 => Err(DbError("yikes".to_string())),
2 => Err(ConnError),
_ => unreachable!()
}
}

Resources