diff --git a/2023-12_ethernet-real-data-rates.md b/2023-12_ethernet-real-data-rates.md
new file mode 100644
index 0000000000000000000000000000000000000000..53714379b78ec53771e58fd67a34d64458d16d3d
--- /dev/null
+++ b/2023-12_ethernet-real-data-rates.md
@@ -0,0 +1,29 @@
+## 2023 12 27 
+
+OK, I'd like to do something similar to [this prior test](https://gitlab.cba.mit.edu/jakeread/teensy-udp) and to the usb-rates in this repo, but using the W5500-EVB-Pico, an RP2040 Pico with a WizNet Ethernet chip bolted onto the end of it. 
+
+For these tests I am interested in maximum data ingest and histograms. 
+
+So let's see, [this](https://goughlui.com/2022/10/23/quick-review-wiznet-w5100s-evb-pico-w5500-evb-pico-development-boards/) notes that we need to do Ethernet.init(17) to set the CS pin properly, but otherwise we can just use the [arduino Ethernet library](https://github.com/arduino-libraries/Ethernet/tree/master/examples) straight up, that's nice.
+
+To connect, we can also wrap the wiz up in a [websocket](https://github.com/skaarj1989/mWebSockets) - maybe - or just write transmission-loss-catching UDP link layer stuff, TBD. 
+
+There's also, ofc, some [messy earle core stuff](https://arduino-pico.readthedocs.io/en/latest/ethernet.html) - they use a different Ethernet stack, it seems. I'm gunsta try the Arduino library first. 
+
+There is also some confusion about [max frame sizes](https://forum.arduino.cc/t/ethernet-udp-is-limited-to-104-bytes/506441) (make sure to read to the end of that post) which I should just test myself. 
+
+## 2023 12 28 
+
+OK, this is looking alive-ish? I should see about getting a UDP ping with Python and then I can record the setup / etc. 
+
+- SET Ethernet Interface (in laptop OS) to use fixed IP,
+  - i.e. I am using 192.168.1.178
+- SET the same to use Subnet Mask 255.255.255.0 
+- Assign Static IP in Arduino to i.e. 192.168.1.177
+
+OK, now I can ping a message down and up, god bless... speed testy time. 
+
+### Polling Speed Test
+
+AFAIK, UDP can source and sink packets at either end of the pipe - it's just a straight IP datagram. It seems like the normal pattern is to use it "transactionally" - i.e. send-req-get-res, and I will need to bootstrap delivery guarantees, etc. I suspect that I will ultimately want TCP here to get those tasty delivery guarantees etc.
+
diff --git a/code/ethernet/ethernet_sink/sink.py b/code/ethernet/ethernet_sink/sink.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca1db1f22a39813ddbbca473e1308b8cdb1ee4b9
--- /dev/null
+++ b/code/ethernet/ethernet_sink/sink.py
@@ -0,0 +1,17 @@
+import socket
+
+# Arduino's network settings
+arduino_ip = '192.168.1.177'
+arduino_port = 8888
+
+# Create a UDP socket
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+# Send a message
+message = b'Hello, Arduino!'
+sock.sendto(message, (arduino_ip, arduino_port))
+print(f'Transmitted...')
+
+# Receive response
+data, addr = sock.recvfrom(1024)
+print(f'Received message: {data}')
diff --git a/code/ethernet/ethernet_source/ethernet_source.ino b/code/ethernet/ethernet_source/ethernet_source.ino
new file mode 100644
index 0000000000000000000000000000000000000000..252b1e80cc9b89ed351ea1fbe41115d9c924eac1
--- /dev/null
+++ b/code/ethernet/ethernet_source/ethernet_source.ino
@@ -0,0 +1,168 @@
+/*
+  DHCP-based IP printer
+
+  This sketch uses the DHCP extensions to the Ethernet library
+  to get an IP address via DHCP and print the address obtained.
+  using an Arduino WIZnet Ethernet shield.
+
+  Circuit:
+   Ethernet shield attached to pins 10, 11, 12, 13
+
+  created 12 April 2011
+  modified 9 Apr 2012
+  by Tom Igoe
+  modified 02 Sept 2015
+  by Arturo Guadalupi
+
+ */
+
+// https://github.com/arduino-libraries/Ethernet/blob/master/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino
+// https://github.com/arduino-libraries/Ethernet/blob/master/examples/UDPSendReceiveString/UDPSendReceiveString.ino
+
+#include <SPI.h>
+#include <Ethernet.h>
+#include <Adafruit_GFX.h>
+#include <Adafruit_SSD1306.h>
+#include <Wire.h>
+
+#define DEBUG_PIN 4
+
+#define SCREEN_WIDTH 128 // OLED display width, in pixels
+#define SCREEN_HEIGHT 64 // OLED display height, in pixels
+
+#define X_POS 0
+#define Y_POS 0
+#define TXT_SIZE 1
+
+// even for displays with i.e. "0x78" printed on the back, 
+// the address that works is 0x3C, IDK 
+#define SCREEN_ADDRESS 0x3C
+
+Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1);
+
+// warning: is blocking, takes ~ 33ms ! 
+void display_print(String msg){
+  display.clearDisplay();
+  display.setCursor(X_POS, Y_POS);
+  display.print(msg);
+  display.display();
+}
+
+// AFAIK we can just make this up for the time being,
+// but should maybe accomodate proper MAC using a MAC IC or sth sth 
+byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
+
+IPAddress ip(192, 168, 1, 177);
+unsigned int localPort = 8888;
+
+char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // is 24, we should test sizes, should go up to nearly 1500 per frame ! 
+char replyBuffer[] = "ack!";
+
+EthernetUDP EUDP;
+
+void setup() {
+  // want that LED,
+  pinMode(LED_BUILTIN, OUTPUT);
+  digitalWrite(LED_BUILTIN, HIGH);
+
+  // a scope debug out 
+  pinMode(DEBUG_PIN, OUTPUT);
+  digitalWrite(DEBUG_PIN, LOW);
+
+  // confirm our I2C pins are here ?
+  Wire1.setSDA(2);
+  Wire1.setSCL(3);
+
+  // initialize the screen,
+  // oddly, SWITCHCAPVCC is the option that works even though OLED is hooked to 5V 
+  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
+  display.clearDisplay();
+  display.display();
+  display.setTextColor(SSD1306_WHITE);
+  display.setTextSize(TXT_SIZE);
+  display.setTextWrap(true);
+  display.dim(false);
+  display_print("bonjour...");
+
+  // You can use Ethernet.init(pin) to configure the CS pin
+  Ethernet.init(17);
+  display_print("ethernet beginning...");
+  
+  // start the Ethernet connection:
+  Ethernet.begin(mac, ip);
+
+  // and the udp link 
+  EUDP.begin(localPort);
+}
+
+uint32_t lastUpdate = 0;
+uint32_t updateInterval = 500;
+
+uint32_t rxCount = 0;
+
+void loop() {
+  size_t len = EUDP.parsePacket();
+  if(len){
+    rxCount ++;
+    display_print("rx " + String(len));
+    EUDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
+  }
+  
+  // report status
+  // TODO: use only one line of the disp for this, 
+  // keep a string-thing somewhere, just update sections of it ? 
+  // i.e. display.println(str1), /// etc... 
+  if(lastUpdate + updateInterval < millis()){
+    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
+    lastUpdate = millis();
+    // write again, 
+    digitalWrite(DEBUG_PIN, HIGH);
+    // display_print("STAMP: " + String(lastUpdate));
+    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
+      display_print("Ethernet shield was not found.");
+    } else if (Ethernet.linkStatus() == LinkOFF) {
+      display_print("Link OFF");
+    } else if (Ethernet.linkStatus() == LinkON){
+      display_print("ON: " + String(rxCount) + " " + (Ethernet.localIP().toString()));
+    } else if (Ethernet.linkStatus() == Unknown){
+      display_print("Link UNKNOWN");
+    }
+    digitalWrite(DEBUG_PIN, LOW);
+  }
+
+  // maintain is required to renew DHCP leases, but we are static-ip'ing this mf'er I think 
+  // see docs: https://www.arduino.cc/reference/en/libraries/ethernet/ethernet.maintain/ 
+  // switch (Ethernet.maintain()) {
+  //   case 1:
+  //     //renewed fail
+  //     display_print("Error: renewed fail");
+  //     break;
+  //   case 2:
+  //     //renewed success
+  //     display_print("Renew, IP: " + Ethernet.localIP());
+  //     break;
+  //   case 3:
+  //     //rebind fail
+  //     display_print("Error: rebind fail");
+  //     break;
+  //   case 4:
+  //     //rebind success
+  //     //print your local IP address:
+  //     display_print("Rebind, IP: " + Ethernet.localIP());
+  //     break;
+
+  //   default:
+  //     //nothing happened
+  //     break;
+  // }
+}
+
+// TODO: run the display from the second core, since 
+// `Wire` uses blocking writes, for when we 
+// are going hardo-perf-mode, 
+
+// void setup1(){
+// }
+
+// void loop1(){
+// }
\ No newline at end of file
diff --git a/code/serial_multi_sink_asyncio/cobs_usb_serial_async.py b/code/usb_serial/serial_multi_sink_asyncio/cobs_usb_serial_async.py
similarity index 100%
rename from code/serial_multi_sink_asyncio/cobs_usb_serial_async.py
rename to code/usb_serial/serial_multi_sink_asyncio/cobs_usb_serial_async.py
diff --git a/code/serial_multi_sink_asyncio/multi_sink_asyncio.py b/code/usb_serial/serial_multi_sink_asyncio/multi_sink_asyncio.py
similarity index 100%
rename from code/serial_multi_sink_asyncio/multi_sink_asyncio.py
rename to code/usb_serial/serial_multi_sink_asyncio/multi_sink_asyncio.py
diff --git a/code/serial_multi_sink_asyncio/multi_sink_blocking.py b/code/usb_serial/serial_multi_sink_asyncio/multi_sink_blocking.py
similarity index 100%
rename from code/serial_multi_sink_asyncio/multi_sink_blocking.py
rename to code/usb_serial/serial_multi_sink_asyncio/multi_sink_blocking.py
diff --git a/code/serial_multi_sink_asyncio/serial_list.py b/code/usb_serial/serial_multi_sink_asyncio/serial_list.py
similarity index 100%
rename from code/serial_multi_sink_asyncio/serial_list.py
rename to code/usb_serial/serial_multi_sink_asyncio/serial_list.py
diff --git a/code/serial_multi_sink_blocking/cobs_usb_serial.py b/code/usb_serial/serial_multi_sink_blocking/cobs_usb_serial.py
similarity index 100%
rename from code/serial_multi_sink_blocking/cobs_usb_serial.py
rename to code/usb_serial/serial_multi_sink_blocking/cobs_usb_serial.py
diff --git a/code/serial_multi_sink_blocking/multi_sink_blocking.py b/code/usb_serial/serial_multi_sink_blocking/multi_sink_blocking.py
similarity index 100%
rename from code/serial_multi_sink_blocking/multi_sink_blocking.py
rename to code/usb_serial/serial_multi_sink_blocking/multi_sink_blocking.py
diff --git a/code/serial_multi_sink_blocking/serial_list.py b/code/usb_serial/serial_multi_sink_blocking/serial_list.py
similarity index 100%
rename from code/serial_multi_sink_blocking/serial_list.py
rename to code/usb_serial/serial_multi_sink_blocking/serial_list.py
diff --git a/code/serial_multi_sink_multiprocessing/cobs_usb_serial_multi.py b/code/usb_serial/serial_multi_sink_multiprocessing/cobs_usb_serial_multi.py
similarity index 100%
rename from code/serial_multi_sink_multiprocessing/cobs_usb_serial_multi.py
rename to code/usb_serial/serial_multi_sink_multiprocessing/cobs_usb_serial_multi.py
diff --git a/code/serial_multi_sink_multiprocessing/multi_sink_multiprocessing.py b/code/usb_serial/serial_multi_sink_multiprocessing/multi_sink_multiprocessing.py
similarity index 100%
rename from code/serial_multi_sink_multiprocessing/multi_sink_multiprocessing.py
rename to code/usb_serial/serial_multi_sink_multiprocessing/multi_sink_multiprocessing.py
diff --git a/code/serial_multi_sink_multiprocessing/plot_stamps.py b/code/usb_serial/serial_multi_sink_multiprocessing/plot_stamps.py
similarity index 100%
rename from code/serial_multi_sink_multiprocessing/plot_stamps.py
rename to code/usb_serial/serial_multi_sink_multiprocessing/plot_stamps.py
diff --git a/code/serial_multi_sink_multiprocessing/serial_list.py b/code/usb_serial/serial_multi_sink_multiprocessing/serial_list.py
similarity index 100%
rename from code/serial_multi_sink_multiprocessing/serial_list.py
rename to code/usb_serial/serial_multi_sink_multiprocessing/serial_list.py
diff --git a/code/serial_sink/cobs_usb_serial.py b/code/usb_serial/serial_sink/cobs_usb_serial.py
similarity index 100%
rename from code/serial_sink/cobs_usb_serial.py
rename to code/usb_serial/serial_sink/cobs_usb_serial.py
diff --git a/code/serial_sink/serial_list.py b/code/usb_serial/serial_sink/serial_list.py
similarity index 100%
rename from code/serial_sink/serial_list.py
rename to code/usb_serial/serial_sink/serial_list.py
diff --git a/code/serial_sink/sink.py b/code/usb_serial/serial_sink/sink.py
similarity index 100%
rename from code/serial_sink/sink.py
rename to code/usb_serial/serial_sink/sink.py
diff --git a/code/serial_sink_simple/serial_list.py b/code/usb_serial/serial_sink_simple/serial_list.py
similarity index 100%
rename from code/serial_sink_simple/serial_list.py
rename to code/usb_serial/serial_sink_simple/serial_list.py
diff --git a/code/serial_sink_simple/sink_simple.py b/code/usb_serial/serial_sink_simple/sink_simple.py
similarity index 100%
rename from code/serial_sink_simple/sink_simple.py
rename to code/usb_serial/serial_sink_simple/sink_simple.py
diff --git a/code/serial_source/COBSUSBSerial.cpp b/code/usb_serial/serial_source/COBSUSBSerial.cpp
similarity index 100%
rename from code/serial_source/COBSUSBSerial.cpp
rename to code/usb_serial/serial_source/COBSUSBSerial.cpp
diff --git a/code/serial_source/COBSUSBSerial.h b/code/usb_serial/serial_source/COBSUSBSerial.h
similarity index 100%
rename from code/serial_source/COBSUSBSerial.h
rename to code/usb_serial/serial_source/COBSUSBSerial.h
diff --git a/code/serial_source/cobs.cpp b/code/usb_serial/serial_source/cobs.cpp
similarity index 100%
rename from code/serial_source/cobs.cpp
rename to code/usb_serial/serial_source/cobs.cpp
diff --git a/code/serial_source/cobs.h b/code/usb_serial/serial_source/cobs.h
similarity index 100%
rename from code/serial_source/cobs.h
rename to code/usb_serial/serial_source/cobs.h
diff --git a/code/serial_source/serial_source.ino b/code/usb_serial/serial_source/serial_source.ino
similarity index 100%
rename from code/serial_source/serial_source.ino
rename to code/usb_serial/serial_source/serial_source.ino
diff --git a/code/serial_source_simple/serial_source_simple.ino b/code/usb_serial/serial_source_simple/serial_source_simple.ino
similarity index 100%
rename from code/serial_source_simple/serial_source_simple.ino
rename to code/usb_serial/serial_source_simple/serial_source_simple.ino