// Collapses a group of packets. This involves incrementing the group // counter and clearing the savedPackets stack by moving top back to 0. // If this is the first group to be collapsed, the collapse time needs // to be set, which marks when this collapsing began. static void collapse(PacketGroup group, CollapseInfo collapseInfo, PacketQueue pktQ) { collapseInfo.count[(byte)group]++; if (collapseInfo.timeSop == 0) { if (!pktQ.isEmpty()) { collapseInfo.timeSop = pktQ.headSop(); } else { collapseInfo.timeSop = pktQ.tailSop(); } } pktQ.clear(); }
// Outputs any packets saved during the collapsing process static void outputSaved(ref int packetnum, ref int signalErrors, CollapseInfo collapseInfo, PacketQueue pktQ) { usbPrintSummaryPacket(ref packetnum, collapseInfo, ref signalErrors); PacketInfo pkt = pktQ.dequeue(); while (pkt != null) { usbPrintPacket(packetnum, pkt, null); packetnum += 1; // Get the next packet or null if empty pkt = pktQ.dequeue(); } }
static void usbDump(int numPackets) { // Packets are saved during the collapsing process PacketQueue pktQ = new PacketQueue(); // Info for the packet that was just read PacketInfo curPacket; // Collapsing counts and time collapsing started CollapseInfo collapseInfo = new CollapseInfo(); CollapseState state = CollapseState.IDLE; bool reRun = false; byte pid = 0; int signalErrors = 0; int packetnum = 0; samplerateKHz = BeagleApi.bg_samplerate(beagle, 0); int idle_samples = IDLE_THRESHOLD * samplerateKHz; // Configure Beagle 480 for realtime capture BeagleApi.bg_usb480_capture_configure(beagle, BeagleUsb480CaptureMode.BG_USB480_CAPTURE_REALTIME, BeagleUsb2TargetSpeed.BG_USB2_AUTO_SPEED_DETECT); // Filter packets intended for the Beagle analyzer. This is only // relevant when one host controller is being used. BeagleApi.bg_usb480_hw_filter_config(beagle, BeagleApi.BG_USB2_HW_FILTER_SELF); // Start the capture if (BeagleApi.bg_enable(beagle, BeagleProtocol.BG_PROTOCOL_USB) != (int)BeagleStatus.BG_OK) { Console.Write("error: could not enable USB capture; exiting...\n"); Environment.Exit(1); } // Output the header... Console.Write("index,time(ns),USB,status,pid,data0 ... dataN(*)\n"); Console.Out.Flush(); // ...then start decoding packets while (packetnum < numPackets || (numPackets == 0)) { curPacket = pktQ.getTail(); curPacket.length = BeagleApi.bg_usb480_read( beagle, ref curPacket.status, ref curPacket.events, ref curPacket.timeSop, ref curPacket.timeDuration, ref curPacket.timeDataOffset, 1024, curPacket.data); curPacket.timeSopNS = timestampToNS(curPacket.timeSop, samplerateKHz); // Exit if observed end of capture if ((curPacket.status & BeagleApi.BG_READ_USB_END_OF_CAPTURE) != 0) { usbPrintSummaryPacket(ref packetnum, collapseInfo, ref signalErrors); break; } // Check for invalid packet or Beagle error if (curPacket.length < 0) { String errorStatus = ""; errorStatus += String.Format("error={0:d}", curPacket.length); usbPrintPacket(packetnum, curPacket, errorStatus); break; } // Check for USB error if (curPacket.status == BeagleApi.BG_READ_USB_ERR_BAD_SIGNALS) { ++signalErrors; } // Set the PID for collapsing state machine below. Treat // KEEP_ALIVEs as packets. if (curPacket.length > 0) { pid = curPacket.data[0]; } else if ((curPacket.events & BeagleApi.BG_EVENT_USB_KEEP_ALIVE) != 0 && (curPacket.status & BeagleApi.BG_READ_USB_ERR_BAD_PID) == 0) { pid = (byte)PacketGroup.KEEP_ALIVE; } else { pid = 0; } // Collapse these packets approprietly: // KEEP_ALIVE* SOF* (IN (ACK|NAK))* (PING NAK)* // (SPLIT (OUT|SETUP) NYET)* (SPLIT IN (ACK|NYET|NACK))* // If the time elapsed since collapsing began is greater than // the threshold, output the counts and zero out the counters. if (curPacket.timeSop - collapseInfo.timeSop >= (ulong)idle_samples) { usbPrintSummaryPacket(ref packetnum, collapseInfo, ref signalErrors); } while (true) { reRun = false; switch (state) { // The initial state of the state machine. Collapse SOFs // and KEEP_ALIVEs. Save IN, PING, or SPLIT packets and // move to the next state for the next packet. Otherwise, // print the collapsed packet counts and the current // packet. case CollapseState.IDLE: switch (pid) { case (byte)PacketGroup.KEEP_ALIVE: collapse(PacketGroup.KEEP_ALIVE, collapseInfo, pktQ); break; case BeagleApi.BG_USB_PID_SOF: collapse(PacketGroup.SOF, collapseInfo, pktQ); break; case BeagleApi.BG_USB_PID_IN: pktQ.savePacket(); state = CollapseState.IN; break; case BeagleApi.BG_USB_PID_PING: pktQ.savePacket(); state = CollapseState.PING; break; case BeagleApi.BG_USB_PID_SPLIT: pktQ.savePacket(); state = CollapseState.SPLIT; break; default: usbPrintSummaryPacket(ref packetnum, collapseInfo, ref signalErrors); if (curPacket.length > 0 || curPacket.events != 0 || (curPacket.status != 0 && curPacket.status != BeagleApi.BG_READ_TIMEOUT)) { usbPrintPacket(packetnum, curPacket, null); packetnum++; } break; } break; // Collapsing IN+ACK or IN+NAK. Otherwise, output any // saved packets and rerun the collapsing state machine // on the current packet. case CollapseState.IN: state = CollapseState.IDLE; switch (pid) { case BeagleApi.BG_USB_PID_ACK: collapse(PacketGroup.IN_ACK, collapseInfo, pktQ); break; case BeagleApi.BG_USB_PID_NAK: collapse(PacketGroup.IN_NAK, collapseInfo, pktQ); break; default: reRun = true; break; } break; // Collapsing PING+NAK case CollapseState.PING: state = CollapseState.IDLE; switch (pid) { case BeagleApi.BG_USB_PID_NAK: collapse(PacketGroup.PING_NAK, collapseInfo, pktQ); break; default: reRun = true; break; } break; // Expecting an IN, OUT, or SETUP case CollapseState.SPLIT: switch (pid) { case BeagleApi.BG_USB_PID_IN: pktQ.savePacket(); state = CollapseState.SPLIT_IN; break; case BeagleApi.BG_USB_PID_OUT: pktQ.savePacket(); state = CollapseState.SPLIT_OUT; break; case BeagleApi.BG_USB_PID_SETUP: pktQ.savePacket(); state = CollapseState.SPLIT_SETUP; break; default: state = CollapseState.IDLE; reRun = true; break; } break; // Collapsing SPLIT+IN+NYET, SPLIT+IN+NAK, SPLIT+IN+ACK case CollapseState.SPLIT_IN: state = CollapseState.IDLE; switch (pid) { case BeagleApi.BG_USB_PID_NYET: collapse(PacketGroup.SPLIT_IN_NYET, collapseInfo, pktQ); break; case BeagleApi.BG_USB_PID_NAK: collapse(PacketGroup.SPLIT_IN_NAK, collapseInfo, pktQ); break; case BeagleApi.BG_USB_PID_ACK: collapse(PacketGroup.SPLIT_IN_ACK, collapseInfo, pktQ); break; default: reRun = true; break; } break; // Collapsing SPLIT+OUT+NYET case CollapseState.SPLIT_OUT: state = CollapseState.IDLE; switch (pid) { case BeagleApi.BG_USB_PID_NYET: collapse(PacketGroup.SPLIT_OUT_NYET, collapseInfo, pktQ); break; default: reRun = true; break; } break; // Collapsing SPLIT+SETUP+NYET case CollapseState.SPLIT_SETUP: state = CollapseState.IDLE; switch (pid) { case BeagleApi.BG_USB_PID_NYET: collapse(PacketGroup.SPLIT_SETUP_NYET, collapseInfo, pktQ); break; default: reRun = true; break; } break; } if (reRun == false) { break; } // The state machine is about to be re-run. This // means that a complete packet sequence wasn't collapsed // and there are packets in the queue that need to be // output before we can process the current packet. outputSaved(ref packetnum, ref signalErrors, collapseInfo, pktQ); } } // Stop the capture BeagleApi.bg_disable(beagle); }
// Dump saved summary information static int usbPrintSummaryPacket(ref int packetNumber, CollapseInfo collapseInfo, ref int signalErrors) { int offset = 0; String summary = ""; if (collapseInfo.count[(byte)PacketGroup.KEEP_ALIVE] > 0 || collapseInfo.count[(byte)PacketGroup.SOF] > 0 || collapseInfo.count[(byte)PacketGroup.PING_NAK] > 0 || collapseInfo.count[(byte)PacketGroup.SPLIT_IN_ACK] > 0 || collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NYET] > 0 || collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NAK] > 0 || collapseInfo.count[(byte)PacketGroup.SPLIT_OUT_NYET] > 0 || collapseInfo.count[(byte)PacketGroup.SPLIT_SETUP_NYET] > 0) { summary += "COLLAPSED "; if (collapseInfo.count[(byte)PacketGroup.KEEP_ALIVE] > 0) { summary += String.Format("[{0:d} KEEP-ALIVE] ", collapseInfo.count[(byte)PacketGroup.KEEP_ALIVE]); } if (collapseInfo.count[(byte)PacketGroup.SOF] > 0) { summary += String.Format("[{0:d} SOF] ", collapseInfo.count[(byte)PacketGroup.SOF]); } if (collapseInfo.count[(byte)PacketGroup.IN_ACK] > 0) { summary += String.Format("[{0:d} IN/ACK] ", collapseInfo.count[(byte)PacketGroup.IN_ACK]); } if (collapseInfo.count[(byte)PacketGroup.IN_NAK] > 0) { summary += String.Format("[{0:d} IN/NAK] ", collapseInfo.count[(byte)PacketGroup.IN_NAK]); } if (collapseInfo.count[(byte)PacketGroup.PING_NAK] > 0) { summary += String.Format("[{0:d} PING/NAK] ", collapseInfo.count[(byte)PacketGroup.PING_NAK]); } #if COMBINE_SPLITS int split_count = collapseInfo.count[(byte)PacketGroup.SPLIT_IN_ACK] + collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NYET] + collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NAK] + collapseInfo.count[(byte)PacketGroup.SPLIT_OUT_NYET] + collapseInfo.count[(byte)PacketGroup.SPLIT_SETUP_NYET]; if (split_count > 0) { summary += String.Format("[{0:d} SPLITS] ", split_count); } #else if (collapseInfo.count[(byte)PacketGroup.SPLIT_IN_ACK] > 0) { summary += String.Format("[{0:d} SPLIT/IN/ACK] ", collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NAK]); } if (collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NYET] > 0) { summary += String.Format("[{0:d} SPLIT/IN/NYET] ", collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NYET]); } if (collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NAK] > 0) { summary += String.Format("[{0:d} SPLIT/IN/NAK] ", collapseInfo.count[(byte)PacketGroup.SPLIT_IN_NAK]); } if (collapseInfo.count[(byte)PacketGroup.SPLIT_OUT_NYET] > 0) { summary += String.Format("[{0:d} SPLIT/OUT/NYET] ", collapseInfo.count[(byte)PacketGroup.SPLIT_OUT_NYET]); } if (collapseInfo.count[(byte)PacketGroup.SPLIT_SETUP_NYET] > 0) { summary += String.Format("[{0:d} SPLIT/SETUP/NYET] ", collapseInfo.count[(byte)PacketGroup.SPLIT_SETUP_NYET]); } #endif usbPrintSummary(packetNumber + offset, collapseInfo.timeSop, summary); offset++; } // Output any signal errors if (signalErrors > 0) { summary += String.Format("<{0:d} SIGNAL ERRORS>", signalErrors); usbPrintSummary(packetNumber + offset, collapseInfo.timeSop, summary); ++offset; } collapseInfo.clear(); packetNumber += offset; return(offset); }