Cleanup and comments

This commit is contained in:
Sebastian 2022-08-28 00:03:06 +02:00
parent 5935541ab2
commit e7c9f5c5cc
1 changed files with 49 additions and 16 deletions

View File

@ -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 {