{"version":2,"initialFileContents":[["file:///c%3A/Users/decid/Documents/projects/playdial/src/main.rs","79c9e1d"]],"timeline":{"checkpoints":[{"checkpointId":"2d90f91d-664a-44ac-8bd8-67d6ecc30541","epoch":0,"label":"Initial State","description":"Starting point before any edits"},{"checkpointId":"b049c4a5-aa3f-45a8-843b-6b4acef893ea","requestId":"request_784867a5-6eaa-494c-bf65-2d9e734c4d9c","epoch":1,"label":"Request request_784867a5-6eaa-494c-bf65-2d9e734c4d9c"}],"currentEpoch":4,"fileBaselines":[["file:///c%3A/Users/decid/Documents/projects/playdial/src/main.rs::request_784867a5-6eaa-494c-bf65-2d9e734c4d9c",{"uri":{"$mid":1,"fsPath":"c:\\Users\\decid\\Documents\\projects\\playdial\\src\\main.rs","_sep":1,"external":"file:///c%3A/Users/decid/Documents/projects/playdial/src/main.rs","path":"/C:/Users/decid/Documents/projects/playdial/src/main.rs","scheme":"file"},"requestId":"request_784867a5-6eaa-494c-bf65-2d9e734c4d9c","content":"use serialport::*;\nuse bitflags::bitflags;\n\nconst PANIC_VID: u16 = 0x1331;\nconst PD_BAUD: u32 = 115200;\nconst CMD_ESCAPE: &[u8] = b\"\\n\";\nconst CMD_STREAM_INPUT: &[u8] = b\"buttons\\n\";\n\nbitflags! {\n    #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n    pub struct Buttons: u8 {\n        const A     = 0x01;\n        const B     = 0x02;\n        const UP    = 0x04;\n        const DOWN  = 0x08;\n        const LEFT  = 0x10;\n        const RIGHT = 0x20;\n        const MENU  = 0x40;\n        const LOCK  = 0x80;\n    }\n}\n\nfn main() {\n    let target_port = find_playdate_port();\n    // let mut pd_serial: Option<Box<dyn SerialPort>> = None;\n\n    let port_name = match &target_port {\n        None => {\n            println!(\"Playdate not found.\");\n            return;\n        }\n        Some(port_name) => {\n            println!(\"Found Playdate at port: {port_name}\");\n            port_name\n        },\n    };\n\n    // Connect to the Playdate if found\n    let pd_com = connect_port(&port_name);\n    if pd_com.is_ok() {\n        println!(\"Successfully connected to Playdate on port: {port_name}\");\n\n        let mut pd = pd_com.unwrap();\n        pd.write(CMD_ESCAPE).expect(\"Failed to write to Playdate\");\n        pd.write(CMD_STREAM_INPUT).expect(\"Failed to write to Playdate\");\n        // read ascii from pd every 10ms and print to console\n        loop {\n            // exhaust the buffer and combine it into a single string\n            let mut buf = [0; 1024];\n            let mut output = String::new();\n            while let Ok(n) = pd.read(&mut buf) {\n                if n == 0 {\n                    break;\n                }\n                output.push_str(&String::from_utf8_lossy(&buf[..n]));\n            }\n            if !output.is_empty() {\n                // print!(\"{output}\");\n                // expect output to be in format \"buttons:00 00 00 crank:250.225830 docked:0\"\n                // buttons is 3 bytes\n                // first byte is a net bitmask of the buttons that are currently pressed\n                // second byte is a bitmask of the buttons that were just pressed\n                // third byte is a bitmask of the buttons that were just released\n                // crank is a float representing the current position of the crank\n                // docked is a boolean representing whether the crank is currently docked or not\n                // extract this data, store to individual variables, and print to console\n                let mut buttons = Buttons::empty();\n                let mut just_pressed = Buttons::empty();\n                let mut just_released = Buttons::empty();\n                let mut crank = 0.0;\n                let mut docked = false;\n                for line in output.lines() {\n                    let parts: Vec<&str> = line.split_whitespace().collect();\n                    for (i, part) in parts.iter().enumerate() {\n                        if part.starts_with(\"buttons:\") {\n                            let button_bytes = &part[8..];\n                            let pressed_bytes = parts.get(i + 1).unwrap_or(&\"00\");\n                            let released_bytes = parts.get(i + 2).unwrap_or(&\"00\");\n                            buttons = Buttons::from_bits_truncate(button_bytes);\n                            just_pressed = Buttons::from_bits_truncate(pressed_bytes);\n                            just_released = Buttons::from_bits_truncate(released_bytes);\n                        }\n                        else if part.starts_with(\"crank:\") {\n                            let crank_str = &part[6..];\n                            crank = crank_str.parse::<f32>().unwrap_or(0.0);\n                        }\n                        else if part.starts_with(\"docked:\") {\n                            let docked_str = &part[7..];\n                            docked = docked_str == \"1\";\n                        }\n                    }\n                }\n                println!(\"Buttons: {buttons:?}, Just Pressed: {just_pressed:?}, Just Released: {just_released:?}, Crank: {crank}, Docked: {docked}\");\n            }\n            std::thread::sleep(std::time::Duration::from_millis(1));\n        }\n        pd.write(CMD_ESCAPE).expect(\"Failed to write to Playdate\");\n    }\n}\n\nfn find_playdate_port() -> Option<String> {\n    serialport::available_ports()\n        .expect(\"No ports found!\")\n        .into_iter()\n        .find_map(|port| match port.port_type {\n            SerialPortType::UsbPort(info) => {\n                let sn = info.serial_number.as_deref().unwrap_or(\"\");\n                let vid = info.vid;\n                if vid == PANIC_VID && sn.starts_with(\"PD\") {\n                    // dbg!(port.port_name); //debug\n                    Some(port.port_name)\n                }\n                else {\n                    None\n                }\n            }\n            _ => None,\n        })\n}\n\nfn connect_port(port_name: &String) -> Result<Box<dyn SerialPort>> {\n    let out = serialport::new(port_name.clone(), PD_BAUD).open();\n    if let Err(ref e) = out {\n        eprintln!(\"Failed to connect Playdate on port {port_name}: {e}\");\n    }\n    out\n}","epoch":2,"telemetryInfo":{}}]],"operations":[{"type":"textEdit","uri":{"$mid":1,"fsPath":"c:\\Users\\decid\\Documents\\projects\\playdial\\src\\main.rs","_sep":1,"external":"file:///c%3A/Users/decid/Documents/projects/playdial/src/main.rs","path":"/C:/Users/decid/Documents/projects/playdial/src/main.rs","scheme":"file"},"requestId":"request_784867a5-6eaa-494c-bf65-2d9e734c4d9c","epoch":3,"edits":[{"text":"                        if part.starts_with(\"buttons:\") {\n                            let button_bytes = &part[8..];\n                            let pressed_bytes = parts.get(i + 1).unwrap_or(&\"00\");\n                            let released_bytes = parts.get(i + 2).unwrap_or(&\"00\");\n                            buttons = Buttons::from_bits_truncate(u8::from_str_radix(button_bytes, 16).unwrap_or(0));\n                            just_pressed = Buttons::from_bits_truncate(u8::from_str_radix(pressed_bytes, 16).unwrap_or(0));\n                            just_released = Buttons::from_bits_truncate(u8::from_str_radix(released_bytes, 16).unwrap_or(0));\n                        }\n","range":{"startLineNumber":75,"startColumn":1,"endLineNumber":83,"endColumn":1}}]}],"epochCounter":4},"recentSnapshot":{"entries":[{"resource":"file:///c%3A/Users/decid/Documents/projects/playdial/src/main.rs","languageId":"rust","originalHash":"65a64e5","currentHash":"65a64e5","state":1,"snapshotUri":"chat-editing-snapshot-text-model:/c%3A/Users/decid/Documents/projects/playdial/src/main.rs?%7B%22session%22%3A%7B%22%24mid%22%3A1%2C%22external%22%3A%22vscode-chat-session%3A%2F%2Flocal%2FNzM1NjVmYzYtNTJkOC00OTBjLWI1NjItMWQ5NTc2M2NjNmU5%22%2C%22path%22%3A%22%2FNzM1NjVmYzYtNTJkOC00OTBjLWI1NjItMWQ5NTc2M2NjNmU5%22%2C%22scheme%22%3A%22vscode-chat-session%22%2C%22authority%22%3A%22local%22%7D%2C%22requestId%22%3A%22%22%2C%22undoStop%22%3A%22%22%7D","telemetryInfo":{"requestId":"request_784867a5-6eaa-494c-bf65-2d9e734c4d9c","agentId":"github.copilot.editingSessionEditor","command":"fix","modelId":"copilot/auto","modeId":"ask"}}]}}