Harald Welte | 0ee2297 | 2020-02-29 11:32:50 +0100 | [diff] [blame] | 1 | module SIMTRACE_Emulation { |
| 2 | |
| 3 | import from General_Types all; |
| 4 | import from Osmocom_Types all; |
| 5 | import from Misc_Helpers all; |
| 6 | |
| 7 | import from USB_PortType all; |
| 8 | import from USB_Types all; |
| 9 | import from USB_Templates all; |
| 10 | import from USB_Component all; |
| 11 | import from USB_PortTypes all; |
| 12 | |
| 13 | import from SIMTRACE_Types all; |
| 14 | import from SIMTRACE_Templates all; |
| 15 | |
| 16 | /* one USB interface */ |
| 17 | type component ST_Emulation_CT extends USB_CT { |
| 18 | var integer g_ep_in; |
| 19 | var integer g_ep_out; |
| 20 | var integer g_ep_irq; |
| 21 | var USB_IF_Params g_pars; |
| 22 | |
| 23 | port ST_USER_PT INOUT; |
| 24 | port ST_USER_PT IRQ; |
| 25 | }; |
| 26 | |
| 27 | type port ST_USER_PT message { |
| 28 | inout SIMTRACE_PDU; |
| 29 | } with { extension "internal" }; |
| 30 | |
| 31 | /* configuration for a ST_Emulation_CT */ |
| 32 | type record USB_IF_Params { |
| 33 | USB_Device_Match usb_dev_match, |
| 34 | integer usb_if_nr |
| 35 | }; |
| 36 | |
| 37 | private const octetstring c_oct261 := '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'O; |
| 38 | |
| 39 | private function f_usb_submit_xfer(USB_endpoint ep, octetstring data := c_oct261, |
| 40 | USB_transfer_type ttype := USB_TRANSFER_TYPE_BULK, |
| 41 | integer tout_ms := 30000) runs on USB_CT |
| 42 | { |
| 43 | var integer req_hdl := f_usb_get_req_hdl(); |
| 44 | var USB_transfer xfer := { |
| 45 | device_hdl := g_dev_hdl, |
| 46 | transfer_hdl := req_hdl, |
| 47 | endpoint := ep, |
| 48 | ttype := ttype, |
| 49 | data := data, |
| 50 | timeout_msec := tout_ms |
| 51 | }; |
| 52 | USB.send(xfer); |
| 53 | } |
| 54 | |
| 55 | /* open libusb device; claim interface; resolve endpoints; submit IN/IRQ transfers */ |
| 56 | function main(USB_IF_Params pars) runs on ST_Emulation_CT { |
| 57 | var USB_Descriptor_Node root; |
| 58 | var integer i_config; |
| 59 | var integer i; |
| 60 | |
| 61 | g_pars := pars; |
| 62 | |
| 63 | f_usb_init(g_pars.usb_dev_match); |
| 64 | |
| 65 | i_config := f_usb_get_config(); |
| 66 | log("USB Configuration: ", i_config); |
| 67 | |
| 68 | root := f_usb_get_desc_tree(); |
| 69 | log(root); |
| 70 | |
| 71 | /* iterate over list of interfaces in current configuration */ |
| 72 | for (i := 0; i < lengthof(root.children[i_config].children); i:=i+1) { |
| 73 | var USB_Descriptor_Node ifn := root.children[i_config].children[i]; |
| 74 | var USB_InterfaceDescriptor ifd := ifn.desc.interface; |
| 75 | var integer j; |
| 76 | if (ifd.bInterfaceNumber != g_pars.usb_if_nr) { |
| 77 | continue; |
| 78 | } |
| 79 | /* determine endpoints inside interface */ |
| 80 | for (j := 0; j < lengthof(ifn.children); j:=j+1) { |
| 81 | if (ischosen(ifn.children[j].desc.endpoint)) { |
| 82 | var USB_EndpointDescriptor epd := ifn.children[j].desc.endpoint; |
| 83 | select (epd.bmAttributes.TranferType) { |
| 84 | case (USB_EpTransfer_BULK) { |
| 85 | if (epd.bEndpointAddress and4b '80'O == '80'O) { |
| 86 | g_ep_in := oct2int(epd.bEndpointAddress); |
| 87 | } else { |
| 88 | g_ep_out := oct2int(epd.bEndpointAddress); |
| 89 | } |
| 90 | } |
| 91 | case (USB_EpTransfer_INTERRUPT) { |
| 92 | g_ep_irq := oct2int(epd.bEndpointAddress); |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | log("USB Endpoints found: IN: ", int2oct(g_ep_in, 1), ", OUT: ", int2oct(g_ep_out, 1), |
| 100 | " IRQ: ", int2oct(g_ep_irq, 1)); |
| 101 | |
| 102 | f_usb_claim_interface(g_dev_hdl, g_pars.usb_if_nr); |
| 103 | |
| 104 | /* submit xfer fro IN and IRQ endpoints */ |
| 105 | f_usb_submit_xfer(g_ep_in); |
| 106 | f_usb_submit_xfer(g_ep_irq, ttype := USB_TRANSFER_TYPE_INTERRUPT); |
| 107 | |
| 108 | var USB_transfer_compl tc; |
| 109 | var SIMTRACE_PDU stpdu_out, stpdu_in; |
| 110 | while (true) { |
| 111 | alt { |
| 112 | [] USB.receive(tr_UsbXfer_compl(g_ep_out, USB_TRANSFER_TYPE_BULK, |
| 113 | USB_TRANSFER_COMPLETED, g_dev_hdl, ?)) { |
| 114 | /* do nothing; normal completion of OUT transfer */ |
| 115 | } |
| 116 | [] USB.receive(tr_UsbXfer_compl(g_ep_in, USB_TRANSFER_TYPE_BULK, |
| 117 | USB_TRANSFER_COMPLETED, g_dev_hdl, ?)) -> value tc { |
| 118 | /* Submit another IN transfer */ |
| 119 | f_usb_submit_xfer(g_ep_in); |
| 120 | stpdu_in := dec_SIMTRACE_PDU(tc.data); |
| 121 | INOUT.send(stpdu_in); |
| 122 | } |
| 123 | [] USB.receive(tr_UsbXfer_compl(g_ep_irq, USB_TRANSFER_TYPE_INTERRUPT, |
| 124 | USB_TRANSFER_COMPLETED, g_dev_hdl, ?))-> value tc { |
| 125 | /* Submit another IRQ transfer */ |
| 126 | f_usb_submit_xfer(g_ep_irq, ttype := USB_TRANSFER_TYPE_INTERRUPT); |
| 127 | stpdu_in := dec_SIMTRACE_PDU(tc.data); |
| 128 | IRQ.send(stpdu_in); |
| 129 | } |
| 130 | [] USB.receive(tr_UsbXfer_compl(g_ep_irq, USB_TRANSFER_TYPE_INTERRUPT, |
| 131 | USB_TRANSFER_TIMED_OUT, g_dev_hdl, ?)) -> value tc { |
| 132 | /* Submit another IRQ transfer */ |
| 133 | f_usb_submit_xfer(g_ep_irq, ttype := USB_TRANSFER_TYPE_INTERRUPT); |
| 134 | } |
| 135 | [] USB.receive(tr_UsbXfer_compl(?, ?, USB_TRANSFER_STALL, g_dev_hdl, ?)) -> value tc { |
| 136 | setverdict(fail, "Unexpected USB_TRANSFER_STALL on EP ", int2hex(tc.endpoint, 2)); |
| 137 | //mtc.stop; |
| 138 | /* Submit another IN transfer */ |
| 139 | f_usb_submit_xfer(tc.endpoint); |
| 140 | } |
| 141 | [] USB.receive(tr_UsbXfer_compl(?, ?, USB_TRANSFER_ERROR, g_dev_hdl, ?)) -> value tc { |
| 142 | setverdict(fail, "Unexpected USB_TRANSFER_ERROR on EP ", int2hex(tc.endpoint, 2)); |
| 143 | mtc.stop; |
| 144 | } |
| 145 | [] USB.receive(tr_UsbXfer_compl(?, ?, USB_TRANSFER_TIMED_OUT, g_dev_hdl, ?)) -> value tc { |
| 146 | setverdict(fail, "Unexpected USB_TRANSFER_TIMED_OUT on EP ", int2hex(tc.endpoint, 2)); |
| 147 | mtc.stop; |
| 148 | } |
| 149 | [] USB.receive(tr_UsbXfer_compl(?, ?, USB_TRANSFER_OVERFLOW, g_dev_hdl, ?)) -> value tc { |
| 150 | setverdict(fail, "Unexpected USB_TRANSFER_OVERFLOW on EP ", int2hex(tc.endpoint, 2)); |
| 151 | mtc.stop; |
| 152 | } |
| 153 | [] USB.receive(tr_UsbXfer_compl(?, ?, ?, g_dev_hdl, ?)) -> value tc { |
| 154 | setverdict(fail, "Unexpected USB Endpoint ", int2hex(tc.endpoint, 2)); |
| 155 | mtc.stop; |
| 156 | } |
| 157 | [] USB.receive(tr_UsbXfer_compl(?, ?, ?, ?, ?)) -> value tc { |
| 158 | setverdict(fail, "Unexpected USB Device ", tc.device_hdl); |
| 159 | mtc.stop; |
| 160 | } |
| 161 | [] USB.receive { |
| 162 | setverdict(fail, "Unexpected Message from USB"); |
| 163 | mtc.stop; |
| 164 | } |
| 165 | |
| 166 | |
| 167 | [] INOUT.receive(SIMTRACE_PDU:?) -> value stpdu_out { |
| 168 | f_usb_submit_xfer(g_ep_out, enc_SIMTRACE_PDU(stpdu_out), tout_ms := 3000); |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | |
| 175 | } |