Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add first methods and structure for PingDevice #9

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ jobs:
quick-tests:
runs-on: ubuntu-latest
steps:
- name: Install libudev
run: sudo apt-get update && sudo apt-get install libudev-dev
- uses: actions/checkout@master
- uses: actions-rs/[email protected]
with:
Expand All @@ -22,6 +24,8 @@ jobs:
needs: quick-tests
runs-on: ubuntu-latest
steps:
- name: Install libudev
run: sudo apt-get update && sudo apt-get install libudev-dev
- uses: actions/checkout@master
- uses: actions-rs/[email protected]
with:
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ quote = "1.0"
proc-macro2 = "1.0.24"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.64"

[dev-dependencies]
serialport = "4.3.0"
clap = { version = "3.1.6", features = ["derive"] }
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,24 @@
# ping-rs
https://docs.bluerobotics.com/ping-rs/ping_rs/

## Using example:

To run examples use:

```shell
cargo run --example ping_common /dev/ttyUSB0 115200
```

Should output:
```shell
Parsing user provided values...
Creating serial connection...
Ping protocol request:
Result: Ok(ProtocolVersionStruct { version_major: 1, version_minor: 0, version_patch: 0, reserved: 0 })
Device information request:
Result: Ok(DeviceInformationStruct { device_type: 1, device_revision: 1, firmware_version_major: 3, firmware_version_minor: 29, firmware_version_patch: 0, reserved: 0 })
Set device_id request:
Result: Ok(AckStruct { acked_id: 100 })
Manual request:
Result: Ok(ProtocolMessage { payload_length: 4, message_id: 5, src_device_id: 1, dst_device_id: 0, payload: [1, 0, 0, 0], checksum: 159 })
```
71 changes: 71 additions & 0 deletions examples/ping_common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use ping_rs::{common, message::ProtocolMessage, PingDevice};
use serialport::ClearBuffer;
use std::time::Duration;

fn main() {
// See mod cli_args bellow.
println!("Parsing user provided values...");
let (port_name, baud_rate) = cli_args::get_cli_args();

println!("Creating serial connection...");
let port = serialport::new(port_name, baud_rate)
.timeout(Duration::from_millis(100))
.open()
.expect("Failed to open serial port");
port.clear(ClearBuffer::All).expect("clear");

let mut ping = PingDevice::new(port);

println!(
"Ping protocol request: \nResult: {:?}",
ping.get_protocol_version()
);
println!(
"Device information request: \nResult: {:?}",
ping.get_device_information()
);
println!(
"Set device_id request: \nResult: {:?}",
ping.set_device_id(1)
);

let request =
common::Messages::GeneralRequest(common::GeneralRequestStruct { requested_id: 5 });
let mut package = ProtocolMessage::new();
package.set_message(&request);
println!("Manual request: \nResult: {:?}", ping.request(package));
}

mod cli_args {
use clap::{Arg, Command};

pub fn get_cli_args() -> (String, u32) {
let matches = Command::new("Ping Common Example")
.about("Execute generic requests from common module")
.disable_version_flag(true)
.arg(
Arg::new("port")
.help("The device path to a serial port")
.required(true),
)
.arg(
Arg::new("baud")
.help("The baud rate to connect at")
.use_value_delimiter(false)
.required(true)
.validator(valid_baud),
)
.get_matches();

let port_name = matches.value_of("port").unwrap().to_string();
let baud_rate = matches.value_of("baud").unwrap().parse::<u32>().unwrap();

(port_name, baud_rate)
}

fn valid_baud(val: &str) -> Result<(), String> {
val.parse::<u32>()
.map(|_| ())
.map_err(|_| "Invalid baud rate".into())
}
}
2 changes: 1 addition & 1 deletion src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl Decoder {
}
}

fn reset(&mut self) {
pub fn reset(&mut self) {
self.state = DecoderState::AwaitingStart1;
self.buffer.clear();
}
Expand Down
109 changes: 109 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include!(concat!(env!("OUT_DIR"), "/mod.rs"));

use message::ProtocolMessage;
use std::io::{Read, Write};

use crate::message::{DeserializeGenericMessage, HEADER};

Expand All @@ -9,6 +10,114 @@ use std::convert::TryFrom;
pub mod decoder;
pub mod message;

#[derive(Debug)]
pub enum PingError {
Io(std::io::Error),
MissingBytes,
ParseError(decoder::ParseError),
UnexpectedStructure,
}

pub struct PingDevice<D> {
port: D,
decoder: decoder::Decoder,
}

impl<D: Read + Write> PingDevice<D> {
pub fn new(port: D) -> Self {
Self {
port,
decoder: decoder::Decoder::new(),
}
}

pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, PingError> {
match self.port.read(buf) {
Ok(value) => Ok(value),
Err(_e) => Err(PingError::Io(_e)),
}
}

pub fn write(&mut self, request: Vec<u8>) -> Result<(), PingError> {
match self.port.write_all(&request) {
Ok(_e) => {
self.port.flush().unwrap();
Ok(_e)
}
Err(_e) => Err(PingError::Io(_e)),
}
}

pub fn request(
&mut self,
request: message::ProtocolMessage,
) -> Result<message::ProtocolMessage, PingError> {
self.write(request.serialized()).unwrap();

let mut serial_buf: Vec<u8> = vec![0; 20];

self.port.read(serial_buf.as_mut_slice()).unwrap();

for byte in &serial_buf {
match self.decoder.parse_byte(byte.clone()) {
decoder::DecoderResult::InProgress => continue,
decoder::DecoderResult::Error(_e) => {
return Err(PingError::ParseError(_e));
}
decoder::DecoderResult::Success(_e) => {
return Ok(_e);
}
}
}
self.decoder.reset();
Err(PingError::MissingBytes)
}

pub fn get_protocol_version(&mut self) -> Result<common::ProtocolVersionStruct, PingError> {
let request =
common::Messages::GeneralRequest(common::GeneralRequestStruct { requested_id: 5 });

let mut package = message::ProtocolMessage::new();
package.set_message(&request);

let answer = self.request(package)?;

match Messages::try_from(&answer) {
Ok(Messages::Common(common::Messages::ProtocolVersion(answer))) => Ok(answer),
_ => Err(PingError::UnexpectedStructure),
}
}

pub fn get_device_information(&mut self) -> Result<common::DeviceInformationStruct, PingError> {
let request =
common::Messages::GeneralRequest(common::GeneralRequestStruct { requested_id: 4 });

let mut package = message::ProtocolMessage::new();
package.set_message(&request);

let answer = self.request(package)?;

match Messages::try_from(&answer) {
Ok(Messages::Common(common::Messages::DeviceInformation(answer))) => Ok(answer),
_ => Err(PingError::UnexpectedStructure),
}
}

pub fn set_device_id(&mut self, device_id: u8) -> Result<common::AckStruct, PingError> {
let request = common::Messages::SetDeviceId(common::SetDeviceIdStruct { device_id });

let mut package = ProtocolMessage::new();
package.set_message(&request);

let answer = self.request(package)?;

match Messages::try_from(&answer) {
Ok(Messages::Common(common::Messages::Ack(answer))) => Ok(answer),
_ => Err(PingError::UnexpectedStructure),
}
}
}

pub fn calculate_crc(pack_without_payload: &[u8]) -> u16 {
return pack_without_payload
.iter()
Expand Down
Loading