// What is plugged in: USB devices listed with their vendors and classes, an adapter looked for by
// id, a configuration descriptor read from a dump, and transfers that fail politely when the
// device is not there. It needs no device: with none, the lists are empty.
//
//   quillo run usb.qwe      then open http://localhost:8080/devices, /names and /descriptor
//
// For a device of your own, USB_DEVICE=1a86:7523 and open /device: on Linux that needs a udev rule.

use "usb.qwer"

let DEVICE = env("USB_DEVICE", "dead:beef")

route GET /devices {
    let all = usb_list(null)?
    { complete: len(all | filter((d) => len(d.id) != 9)) == 0, count_agrees: usb_count(null)? == len(all), storage: usb_count({ class: 8 })? >= 0 }
}

route GET /look {
    let found = usb_list(DEVICE)?
    if len(found) == 0 { return { plugged_in: false, count: usb_count(DEVICE)?, none_of_vendor: usb_list({ vendor: "dead" })? } }
    { plugged_in: true, device: found[0], descriptors: usb_descriptors(DEVICE) }
}

route GET /names = {
    ftdi: usb_vendor_name("0403")?,
    pico: usb_vendor_name("2e8a")?,
    unknown: usb_vendor_name("dead")?,
    bad_id: usb_vendor_name("nope").error,
    storage: usb_class_name(8)?,
    hid: usb_class_name(3)?,
    own: usb_class_name(255)?,
    bad_class: usb_class_name(300).error,
}

// A CDC serial adapter's configuration descriptor, as lsusb would dump it: control interface
// with one interrupt endpoint, data interface with bulk in and out.
let CDC = "090243000201008032" + "090400000102020100" + "052400100105240101" + "0104240202" + "0524060001"
    + "070582030800FF" + "09040100020A000000" + "07050102400000" + "07058102400000"

route GET /descriptor = usb_parse_config(CDC)?

route GET /failures = {
    gone: usb_bulk_read("dead:beef", 0, 129, 64, 100).error,
    gone_write: usb_bulk_write("dead:beef", 0, 1, [1, 2], 100).error,
    gone_control: usb_control_read("dead:beef", { type: "vendor", request: 1, length: 4 }).error,
    gone_info: usb_descriptors("dead:beef").error,
    in_for_out: usb_bulk_read("dead:beef", 0, 1, 64, 100).error,
    out_for_in: usb_bulk_write("dead:beef", 0, 129, [1], 100).error,
    bad_selector: usb_list("dead").error,
    bad_filter: usb_list({ colour: "red" }).error,
    nothing_named: usb_descriptors(null).error,
    short: usb_parse_config("0902").error,
}
