1extern crate core;
2#[macro_use]
3extern crate lazy_static;
4
5use libftd2xx::{DeviceInfo, Ftdi, FtdiCommon, FtStatus, TimeoutError};
6use log::debug;
7use crate::carts::{Cic, SaveType};
8use crate::carts::sixtyfourdrive::SixtyFourDrive;
9use crate::unfloader::DebugResponse;
10
11pub mod carts;
12pub mod unfloader;
13
14#[derive(Debug, PartialEq)]
15pub enum Error {
16 FtdiStatus(FtStatus),
17 FtdiTimeout(TimeoutError),
18
19 CommunicationFailed(String),
20
21 Unsupported,
22}
23impl From<FtStatus> for Error {
24 fn from(value: FtStatus) -> Self {
25 Self::FtdiStatus(value)
26 }
27}
28impl From<TimeoutError> for Error {
29 fn from(value: TimeoutError) -> Self {
30 Self::FtdiTimeout(value)
31 }
32}
33
34pub type Result<T> = std::result::Result<T, Error>;
35
36pub trait Flashcart {
37 fn upload_rom(&mut self, data: &[u8]) -> Result<()>;
38 fn download_rom(&mut self, length: u32) -> Result<Vec<u8>>;
39
40 fn set_cic(&mut self, cic: Cic) -> Result<()>;
41 fn set_savetype(&mut self, savetype: SaveType) -> Result<()>;
42
43 fn recv_debug(&mut self) -> Result<DebugResponse>;
44 fn send_debug(&mut self) -> Result<()>;
45 fn info(&mut self) -> Result<DeviceInfo>;
46}
47
48
49pub fn carts() -> Result<Vec<Box<dyn Flashcart>>> {
50 let mut carts = vec![];
51
52 for info in libftd2xx::list_devices()? {
53 debug!("Device detected: {info:?}");
54 match from_info(&info) {
55 Ok(cart) => carts.push(cart),
56 Err(_) => (),
57 }
58 }
59
60 Ok(carts)
61}
62
63pub fn from_serial<S: AsRef<str>>(serial: S) -> Result<Box<dyn Flashcart>> {
64 let mut device = Ftdi::with_serial_number(serial.as_ref())?;
65 let info = device.device_info()?;
66 device.close()?;
67
68 from_info(&info)
69}
70
71pub fn from_info(info: &DeviceInfo) -> Result<Box<dyn Flashcart>> {
72 match (info.vendor_id, info.product_id, info.description.as_str()) {
73 (0x0403, 0x6010, "64drive USB device A") => Ok(Box::new(SixtyFourDrive::new(Ftdi::with_serial_number(&info.serial_number)?)?)),
74 (0x0403, 0x6014, "64drive USB device") => Ok(Box::new(SixtyFourDrive::new(Ftdi::with_serial_number(&info.serial_number)?)?)),
75 (0x0403, 0x6001, "FT245R USB FIFO") => todo!("everdrive"),
76 (0x0403, 0x6014, "SC64") => todo!("summercart64"),
77
78 _ => Err(Error::Unsupported)
79 }
80}