Cleanup and comments
This commit is contained in:
parent
5935541ab2
commit
e7c9f5c5cc
63
src/usb.rs
63
src/usb.rs
|
@ -29,7 +29,6 @@ pub async fn usb_task(
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let config = embassy_usb::Config::new(0xc0de, 0xcafe);
|
let config = embassy_usb::Config::new(0xc0de, 0xcafe);
|
||||||
//config.max_packet_size_0 = 64;
|
|
||||||
|
|
||||||
// Create embassy-usb DeviceBuilder using the driver and config.
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
// It needs some buffers for building the descriptors.
|
// It needs some buffers for building the descriptors.
|
||||||
|
@ -38,7 +37,7 @@ pub async fn usb_task(
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 7];
|
let mut control_buf = [0; 7];
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut usb_state = State::new();
|
||||||
|
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
driver,
|
driver,
|
||||||
|
@ -51,36 +50,47 @@ pub async fn usb_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create classes on the builder.
|
// Create classes on the builder.
|
||||||
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
|
let mut class = CdcAcmClass::new(&mut builder, &mut usb_state, 64);
|
||||||
|
|
||||||
// Build the builder.
|
// Build the builder.
|
||||||
let mut usb = builder.build();
|
let mut usb = builder.build();
|
||||||
|
|
||||||
// Do stuff with the class!
|
// Create a future to handle incomming usb packets
|
||||||
let usb_handler_fut = async {
|
let usb_handler_fut = async {
|
||||||
|
// Initialize the current position in case we get a B or C command,
|
||||||
|
// before we get the first the update via pos_receiver
|
||||||
let mut current_pos = AzElPair { az: 0, el: 0 };
|
let mut current_pos = AzElPair { az: 0, el: 0 };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// No much used doing anything until we have a usb connection
|
||||||
class.wait_connection().await;
|
class.wait_connection().await;
|
||||||
defmt::info!("USB connected");
|
defmt::info!("USB connected");
|
||||||
|
// Allocate a space for incomming usb data packets
|
||||||
let mut packet = [0; 64];
|
let mut packet = [0; 64];
|
||||||
|
// Allocate a string to act as buffer to pares the packets linewise
|
||||||
let mut buffer: String<64> = String::new();
|
let mut buffer: String<64> = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let n = match select(class.read_packet(&mut packet), pos_receiver.recv()).await {
|
let n = match select(class.read_packet(&mut packet), pos_receiver.recv()).await {
|
||||||
|
// The read_packet furture returned either usb data or an error.
|
||||||
Either::First(res) => match res {
|
Either::First(res) => match res {
|
||||||
|
// In case of an error break the loop and treat it like an usb disconnect
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
|
// In case of an error break the loop and treat it like an usb disconnect
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
defmt::error!("Unable to read packet: {}", err);
|
defmt::error!("Unable to read packet: {}", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// The pos_receiver future returned a position update from moment task.
|
||||||
|
// Just update position and restart loop.
|
||||||
Either::Second(pair) => {
|
Either::Second(pair) => {
|
||||||
current_pos = pair;
|
current_pos = pair;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Append the data in the packet buffer to the buffer string
|
||||||
for byte in &packet[..n] {
|
for byte in &packet[..n] {
|
||||||
if buffer.len() == 64 {
|
if buffer.len() == 64 {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
@ -88,91 +98,113 @@ pub async fn usb_task(
|
||||||
buffer.push(*byte as char).unwrap();
|
buffer.push(*byte as char).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the buffer string contains a '\r'
|
||||||
let line_end = match buffer.rfind('\r') {
|
let line_end = match buffer.rfind('\r') {
|
||||||
|
// Carriage return found, keep the index
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
|
// No carriage return, wait for the next package
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
defmt::info!("Line buffer: {:x}", buffer.as_bytes());
|
// The is a non-zero amount of characters before the carriage return
|
||||||
|
|
||||||
if line_end > 0 {
|
if line_end > 0 {
|
||||||
|
// Try the parse the slice leading up to linend as a GS323 command
|
||||||
let cmd = parse_command(&buffer.as_str()[..line_end]);
|
let cmd = parse_command(&buffer.as_str()[..line_end]);
|
||||||
defmt::info!("Command: {}", cmd);
|
defmt::info!("Command: {}", cmd);
|
||||||
|
|
||||||
|
// Reverse some space for a respose to the command
|
||||||
let mut resp: String<16> = String::new();
|
let mut resp: String<16> = String::new();
|
||||||
match cmd {
|
match cmd {
|
||||||
Gs232Cmd::GetAl => {
|
// Get Azimuth command. Respond with last known azimuth
|
||||||
|
Gs232Cmd::GetAz => {
|
||||||
uwrite!(&mut resp, "AZ={}\r", current_pos.az).unwrap();
|
uwrite!(&mut resp, "AZ={}\r", current_pos.az).unwrap();
|
||||||
}
|
}
|
||||||
Gs232Cmd::GetEz => {
|
// Get Elevation comman. Respond with last known elevation
|
||||||
|
Gs232Cmd::GetEl => {
|
||||||
uwrite!(&mut resp, "EL={}\r", current_pos.el).unwrap();
|
uwrite!(&mut resp, "EL={}\r", current_pos.el).unwrap();
|
||||||
}
|
}
|
||||||
Gs232Cmd::GetAlEz => {
|
// Get Azimuth and Elevation. Respond with last known pair
|
||||||
|
Gs232Cmd::GetAzEl => {
|
||||||
uwrite!(&mut resp, "AZ={} EL={}\r", current_pos.az, current_pos.el)
|
uwrite!(&mut resp, "AZ={} EL={}\r", current_pos.az, current_pos.el)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
// Move to command. Send to movement task. Respond with empty line.
|
||||||
Gs232Cmd::MoveTo(_) => {
|
Gs232Cmd::MoveTo(_) => {
|
||||||
cmd_sender.send(cmd).await;
|
cmd_sender.send(cmd).await;
|
||||||
resp.push_str("\r").unwrap();
|
resp.push_str("\r").unwrap();
|
||||||
}
|
}
|
||||||
|
// Stop command. Send to movement task. Respond with empty line.
|
||||||
Gs232Cmd::Stop => {
|
Gs232Cmd::Stop => {
|
||||||
cmd_sender.send(cmd).await;
|
cmd_sender.send(cmd).await;
|
||||||
resp.push_str("\r").unwrap();
|
resp.push_str("\r").unwrap();
|
||||||
}
|
}
|
||||||
|
// Unknown command or parser error. Complain and do nothing.
|
||||||
_ => {
|
_ => {
|
||||||
defmt::error!("Uknown command: {}", &buffer.as_str()[..line_end]);
|
defmt::error!("Uknown command: {}", &buffer.as_str()[..line_end]);
|
||||||
resp.push_str("Unkown command!\r").unwrap();
|
resp.push_str("Unkown command!\r").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write the response back via USB
|
||||||
match class.write_packet(resp.as_bytes()).await {
|
match class.write_packet(resp.as_bytes()).await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
// Error treat like broken usb connection
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
defmt::error!("Unable to write packet: {}", err);
|
defmt::error!("Unable to write packet: {}", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Drop the processed line from the buffer
|
||||||
buffer = String::from(&buffer.as_str()[line_end + 1..]);
|
buffer = String::from(&buffer.as_str()[line_end + 1..]);
|
||||||
}
|
}
|
||||||
defmt::info!("USB disconnected");
|
defmt::info!("USB disconnected");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Run the ubs and handler future both to completion.
|
||||||
|
// None of the ever completes, but they will still be polled continously.
|
||||||
join(usb.run(), usb_handler_fut).await;
|
join(usb.run(), usb_handler_fut).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enum for the GS232 commands
|
||||||
#[derive(Format, PartialEq)]
|
#[derive(Format, PartialEq)]
|
||||||
pub enum Gs232Cmd {
|
pub enum Gs232Cmd {
|
||||||
Unkown,
|
Unkown,
|
||||||
GetAl,
|
GetAz,
|
||||||
GetEz,
|
GetEl,
|
||||||
GetAlEz,
|
GetAzEl,
|
||||||
MoveTo(AzElPair),
|
MoveTo(AzElPair),
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse a GS232 commmand from a string slice
|
||||||
fn parse_command(data: &str) -> Gs232Cmd {
|
fn parse_command(data: &str) -> Gs232Cmd {
|
||||||
match data.chars().nth(0).unwrap() {
|
match data.chars().nth(0).unwrap() {
|
||||||
'B' => {
|
'B' => {
|
||||||
|
// Get Az command. Format 'B\r'
|
||||||
if data.len() == 1 {
|
if data.len() == 1 {
|
||||||
Gs232Cmd::GetAl
|
Gs232Cmd::GetAz
|
||||||
} else {
|
} else {
|
||||||
Gs232Cmd::Unkown
|
Gs232Cmd::Unkown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
'C' => {
|
'C' => {
|
||||||
|
// Get AZ and EL. Format 'C2\r'
|
||||||
if data.len() == 2 && data.chars().nth(1).unwrap() as char == '2' {
|
if data.len() == 2 && data.chars().nth(1).unwrap() as char == '2' {
|
||||||
Gs232Cmd::GetAlEz
|
Gs232Cmd::GetAzEl
|
||||||
|
// Get EL only 'C\r'
|
||||||
} else if data.len() == 1 {
|
} else if data.len() == 1 {
|
||||||
Gs232Cmd::GetEz
|
Gs232Cmd::GetEl
|
||||||
} else {
|
} else {
|
||||||
Gs232Cmd::Unkown
|
Gs232Cmd::Unkown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
'W' => {
|
'W' => {
|
||||||
|
// Set position 'Waaa eee\r' with azimuth aaa and elevation eee.
|
||||||
|
// Fortunately rotcld will prepend zeros, so there will always be 3 digits per number.
|
||||||
if data.len() == 8 {
|
if data.len() == 8 {
|
||||||
if let Ok(az) = data[1..4].parse::<u16>() {
|
if let Ok(az) = data[1..4].parse::<u16>() {
|
||||||
if let Ok(el) = data[5..].parse::<u16>() {
|
if let Ok(el) = data[5..].parse::<u16>() {
|
||||||
|
@ -189,6 +221,7 @@ fn parse_command(data: &str) -> Gs232Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
'S' => {
|
'S' => {
|
||||||
|
// Stop command. Format 'S\r'
|
||||||
if data.len() == 1 {
|
if data.len() == 1 {
|
||||||
Gs232Cmd::Stop
|
Gs232Cmd::Stop
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue