Răsfoiți Sursa

gw bandwidth: Check integrity of USB comms during bandwidth test.

Keir Fraser 3 ani în urmă
părinte
comite
4b82ef4741

+ 1 - 0
inc/cdc_acm_protocol.h

@@ -197,6 +197,7 @@ struct packed gw_erase_flux {
 /* CMD_SINK_SOURCE_BYTES */
 struct packed gw_sink_source_bytes {
     uint32_t nr_bytes;
+    uint32_t seed;
 };
 
 /* CMD_{GET,SET}_PARAMS, index 0 */

+ 24 - 5
scripts/greaseweazle/tools/bandwidth.py

@@ -9,34 +9,53 @@
 
 description = "Report the available USB bandwidth for the Greaseweazle device."
 
-import sys
+import struct, sys
 
 from timeit import default_timer as timer
 
 from greaseweazle.tools import util
 from greaseweazle import usb as USB
 
+def generate_random_buffer(nr, seed):
+    dat = bytearray()
+    r = seed
+    for i in range(nr):
+        dat.append(r&255)
+        if r & 1:
+            r = (r>>1) ^ 0x80000062
+        else:
+            r >>= 1
+    return dat
+
 def measure_bandwidth(usb, args):
     print()
     print("%19s%-7s/   %-7s/   %-7s" % ("", "Min.", "Mean", "Max."))
 
-    w_nr = 1000000
+    seed = 0x12345678
+    w_nr = r_nr = 1000000
+    buf = generate_random_buffer(w_nr, seed)
+
     start = timer()
-    usb.sink_bytes(w_nr)
+    ack = usb.sink_bytes(buf, seed)
     end = timer()
     av_w_bw = (w_nr * 8) / ((end-start) * 1e6)
     min_w_bw, max_w_bw = usb.bw_stats()
     print("Write Bandwidth: %8.3f / %8.3f / %8.3f Mbps"
           % (min_w_bw, av_w_bw, max_w_bw))
+    if ack != 0:
+        print("ERROR: USB write data garbled (Host -> Device)")
+        return
     
-    r_nr = 1000000
     start = timer()
-    usb.source_bytes(r_nr)
+    sbuf = usb.source_bytes(r_nr, seed)
     end = timer()
     av_r_bw = (r_nr * 8) / ((end-start) * 1e6)
     min_r_bw, max_r_bw = usb.bw_stats()
     print("Read Bandwidth:  %8.3f / %8.3f / %8.3f Mbps"
           % (min_r_bw, av_r_bw, max_r_bw))
+    if sbuf is not None and sbuf != buf:
+        print("ERROR: USB read data garbled (Device -> Host)")
+        return
 
     est_min_bw = 0.9 * min(min_r_bw, min_w_bw)
     print()

+ 10 - 10
scripts/greaseweazle/tools/util.py

@@ -264,17 +264,17 @@ def usb_reopen(usb, is_update):
     raise serial.SerialException('Could not reopen port after mode switch')
 
 
-def usb_open(devicename, is_update=False, mode_check=True):
+def print_update_instructions(usb):
+    print("To perform an Update:")
+    if not usb.jumperless_update:
+        print(" - Disconnect from USB")
+        print(" - Install the Update Jumper at pins %s"
+              % ("RXI-TXO" if usb.hw_model != 1 else "DCLK-GND"))
+        print(" - Reconnect to USB")
+    print(" - Run \"gw update\" to install firmware v%u.%u" %
+          (version.major, version.minor))
 
-    def print_update_instructions(usb):
-        print("To perform an Update:")
-        if not usb.jumperless_update:
-            print(" - Disconnect from USB")
-            print(" - Install the Update Jumper at pins %s"
-                  % ("RXI-TXO" if usb.hw_model != 1 else "DCLK-GND"))
-            print(" - Reconnect to USB")
-        print(" - Run \"gw update\" to install firmware v%u.%u" %
-              (version.major, version.minor))
+def usb_open(devicename, is_update=False, mode_check=True):
 
     if devicename is None:
         devicename = find_port()

+ 25 - 17
scripts/greaseweazle/usb.py

@@ -458,25 +458,33 @@ class Unit:
 
     ## source_bytes:
     ## Command Greaseweazle to source 'nr' garbage bytes.
-    def source_bytes(self, nr):
-        self._send_cmd(struct.pack("<2BI", Cmd.SourceBytes, 6, nr))
-        while nr > 0:
-            self.ser.read(1)
-            waiting = self.ser.in_waiting
-            self.ser.read(waiting)
-            nr -= 1 + waiting
-
+    def source_bytes(self, nr, seed):
+        try:
+            self._send_cmd(struct.pack("<2B2I", Cmd.SourceBytes, 10, nr, seed))
+            dat = self.ser.read(nr)
+        except CmdError as error:
+            if error.code != Ack.BadCommand:
+                raise
+            # Firmware v0.28 and earlier
+            self._send_cmd(struct.pack("<2BI", Cmd.SourceBytes, 6, nr))
+            self.ser.read(nr)
+            dat = None
+        return dat
 
     ## sink_bytes:
-    ## Command Greaseweazle to sink 'nr' garbage bytes.
-    def sink_bytes(self, nr):
-        self._send_cmd(struct.pack("<2BI", Cmd.SinkBytes, 6, nr))
-        dat = bytes(1024*1024)
-        while nr > len(dat):
-            self.ser.write(dat)
-            nr -= len(dat)
-        self.ser.write(dat[:nr])
-        self.ser.read(1) # Sync with Greaseweazle
+    ## Command Greaseweazle to sink given data buffer.
+    def sink_bytes(self, dat, seed):
+        try:
+            self._send_cmd(struct.pack("<2BII", Cmd.SinkBytes, 10,
+                                       len(dat), seed))
+        except CmdError as error:
+            if error.code != Ack.BadCommand:
+                raise
+            # Firmware v0.28 and earlier
+            self._send_cmd(struct.pack("<2BI", Cmd.SinkBytes, 6, len(dat)))
+        self.ser.write(dat)
+        (ack,) = struct.unpack("B", self.ser.read(1))
+        return ack
 
 
     ## bw_stats:

+ 31 - 2
src/floppy.c

@@ -1181,13 +1181,23 @@ static struct {
     unsigned int todo;
     unsigned int min_delta;
     unsigned int max_delta;
+    unsigned int status;
+    uint32_t rand;
 } ss;
 
+static uint32_t ss_rand_next(uint32_t x)
+{
+    return (x&1) ? (x>>1) ^ 0x80000062 : x>>1;
+}
+
 static void sink_source_prep(const struct gw_sink_source_bytes *ssb)
 {
     ss.min_delta = INT_MAX;
     ss.max_delta = 0;
     ss.todo = ssb->nr_bytes;
+    ss.rand = ssb->seed;
+    ss.status = ACK_OKAY;
+    usb_packet.ready = FALSE;
 }
 
 static void ss_update_deltas(int len)
@@ -1214,9 +1224,21 @@ static void ss_update_deltas(int len)
 
 static void source_bytes(void)
 {
+    int i;
+
+    if (!usb_packet.ready) {
+        for (i = 0; i < usb_bulk_mps; i++) {
+            usb_packet.data[i] = (uint8_t)ss.rand;
+            ss.rand = ss_rand_next(ss.rand);
+        }
+        usb_packet.ready = TRUE;
+    }
+
     if (!ep_tx_ready(EP_TX))
         return;
 
+    usb_packet.ready = FALSE;
+
     if (ss.todo < usb_bulk_mps) {
         floppy_state = ST_command_wait;
         floppy_end_command(usb_packet.data, ss.todo);
@@ -1230,13 +1252,13 @@ static void source_bytes(void)
 
 static void sink_bytes(void)
 {
-    int len;
+    int i, len;
 
     if (ss.todo == 0) {
         /* We're done: Wait for space to write the ACK byte. */
         if (!ep_tx_ready(EP_TX))
             return;
-        u_buf[0] = ACK_OKAY;
+        u_buf[0] = ss.status;
         floppy_state = ST_command_wait;
         floppy_end_command(u_buf, 1);
         return; /* FINISHED */
@@ -1251,6 +1273,13 @@ static void sink_bytes(void)
     usb_read(EP_RX, usb_packet.data, len);
     ss.todo = (ss.todo <= len) ? 0 : ss.todo - len;
     ss_update_deltas(len);
+
+    /* Check data. */
+    for (i = 0; i < len; i++) {
+        if (usb_packet.data[i] != (uint8_t)ss.rand)
+            ss.status = ACK_BAD_COMMAND;
+        ss.rand = ss_rand_next(ss.rand);
+    }
 }