Jared Sanson

Tags

 

You are likely no stranger to the work-from-home environment many find ourselves in these days, and if you're like me and have a separate work & play machine but share a single monitor, you will want a KVM to save the hassle of unplugging things at the end of each day.

Unfortunately there don't seem to be any cheap DisplayPort KVMs out there. The cheapest I could find (at time of writing) was $200USD! Surely something which in theory should be just a high-bandwidth mux shouldn't cost so much, so I set about creating my own...

The final hardware is simple and elegant:

It takes your two DP inputs (plus USB2.0), and with the press of either button you can route either input through to the DP+USB output.

The DP source that gets deactivated simply sees it as if the cable had been unplugged, and the monitor will see it as if you've swapped the cable between two machines, and will reconfigure itself accordingly.

This behaviour may cause some minor annoyance as your OS shuffles things around to match the new resolution, but unfortunately the only way to prevent this behaviour would be to write firmware to fake the handshaking to the monitor.

The Design

At some point I stumbled upon the Texas Instruments HD3SS215 HDMI/DP 2:1 mux, and at ~$10 a chip it seemed perfect for creating a simple DP switch. It's very simple on the surface - it allows you to select between two sets of 5 high-speed differential pairs (bi-directional!) with just a single pin (high / low).

Now after working with firmware all day for my job, I wasn't too keen to spend my little free time writing firmware for this (plus I figured I might actually finish it if I kept the scope small...) so I opted to use a simple SR flip-flop circuit and two physical buttons to allow selection of the appropriate output. This removed the need for any fancy HID-keyboard sniffing, and should be rock-solid since there's no firmware that can go haywire!

I also wanted to switch a USB2.0 keyboard and mouse which would normally necessitate another mux chip, but I saw that the HD3SS215 had mux lines to support both DP & HDMI side-band signals, and since I wasn't supporting HDMI I figured I could probably abuse these to switch USB2.0. Unfortunately the datasheet didn't indicate what speed these signals were rated for, so I just winged it and hoped it would work in my prototype... fortunately it did!

Now the trickiest part of the design is the high-speed DisplayPort signals which operate in the GHz range. This requires careful routing and impedance-controlled layout. Fortunately this has become easier in the latest Kicad with the addition of differential signal tools.

Rev1 Mistakes

No project is perfect from the start - in my first prototype I encountered a few major issues:

  1. The flip-flop circuit's inputs were inverted (I neglected to note that the inputs need to be active-low)
  2. The USB input connectors were flipped in respect to the DP input connectors. Oops.
  3. The DP connectors are a bit sloppy, and if you move the cable the signal will drop out breifly.

These issues have been corrected (but not tested) in the latest version on Github.

Additionally, I added extra test points and 0R resistors in Rev2 to allow for reconfiguration of the DDC/AUX lines, in case I want to make it smarter in the future.

Manufacturing

You are free to build your own!

The design files are licensed under the CERN OHL-S v2 license, which states that you can modify the design as long as you keep the terms of the original license and make your changes available (similar to GPL). You are also free to sell it, but I ask that you retain attribution on the silkscreen.

Now that you understand the above disclaimer, you can find the full KiCad sources on GitHub.

Since DP operates in the GHz range, the PCB must be impedance controlled, and requires a 4 layer stackup. I used JLCPCB's 4-layer 'JLC7628' PCB with a dielectric constant of 4.6, and a black solder mask.

It should be relatively straight forward to solder if you have any experience with 0603 resistors and QFN parts. It should be easily achievable with a hotplate, hot air gun, or reflow oven.

That being said, I was not immediately successful when soldering with a hotplate - one of the DP channels didn't work at first, but I was able to resolve it by reflowing the solder on the QFN chip and DP connector. If you encounter similar issues, try reflowing things, and watch out for solder bridges!!

If you do end up building this, let me know in the comments

View Comments...

Datasheets2 is a simple datasheet/document/PDF organizer that allows you to quickly search your collection and open specific files.

This is a port of my original Datasheets Indexer utility, which was written in Delphi/Pascal. I no longer write Pascal, and much prefer C#+WPF for my utility apps!

The entire utility app is packaged into a single exe, with an optional configuration file, enabling a single-file portable deployment!

There is no telemetry, and no internet traffic except for when an online search is invoked. By default Datasheets2 does not perform online searches to protect your privacy.

Usage

  • Place the executable in a directory containing documents.

  • Drag'n'drop files and URLs onto the window to add datasheets to your library (Tip: Hold SHIFT to move instead of copy)

  • Type your keyword and press ENTER to open the first matching document.

  • If no document is found in your library, and you have configured online search, the keyword will initiate a search for the datasheet using the configured search providers

Configuration

You can configure the app by editing Datasheets2.exe.config, which should be placed next to the exe. If you rename the exe, you must also rename this file.

Datasheets2 can search Octopart and other sources for datasheets, but to do this you will need to register for an Octopart API key, and enable it in your local configuration. See the Github project for more information...

License

The source code is licensed under GPL3.0, but you may use the app itself for any purpose.

Enjoy!

View Comments...

In 2008 I wrote an incomplete 3D game called 'Tiberian Tanks'.

I wouldn't be able to release it because it uses copyrighted assets from the long since disbanded Red Alert 2 / Tiberian Sun games, but I thought it might be worth writing about as an interesting project from my past.

When I wrote this engine I had no knowledge of how to code properly (I was self-taught until I got to University), and things like Unreal Engine / Unity were not really a thing. I also had an obsession with reinventing the wheel (Actually I still do 😅).

The game is written in Delphi, and uses OpenGL. There is no scene graph. Instead things are drawn in-order with plain OpenGL calls, so transparency never worked quite right (see the loading screen!)

For those unaware of how a 3D engine should work, you must draw triangles from back to front so that the front triangles can blend with what's already on the screen. The right way to do this is by storing all your meshes into a giant scene graph, clip it (cull) so that you're only looking at meshes within the current view (frustum), then iterate through the graph from back to front. This is one of the many things that engines like Unreal / Unity do for free!

Delphi/ObjectPascal itself was an interesting language. It's very different from the usual C-like languages. For example, here's part of the main Timer procedure which is responsible for drawing everything:

procedure TfmMain.TimerTimer(Sender: TObject);
var
  Rect: array[0..3] of TVector3f;
  fnt: pGLFont;
  i: integer;
  LPos: array[0..3] of GLFloat;
begin
  DoQuit := false;
  FPSTime := GetTickCount;
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glLoadIdentity;

  // ...snip...

  glBindTexture(GL_TEXTURE_2D, SkyboxTex[0].Tex);
  glBegin(GL_QUADS);
    glTexCoord2f(0,0);  glVertex3f(-1, 1,-1);
    glTexCoord2f(1,0);  glVertex3f( 1, 1,-1);
    glTexCoord2f(1,1);  glVertex3f( 1, 0,-1);
    glTexCoord2f(0,1);  glVertex3f(-1, 0,-1);
  glEnd;

  // ...snip...

  SwapBuffers(DC);

  cSetStatus('FPS: '+floattostr(round(FPS*10)/10));
end;

One thing Delphi did well was that it had a great separation of code (implementation) and definition (interface). This made compling code fast and importing compiled libraries extremely easy.

As far as I know, no other mainstream language did this

  • C/C++ have source and headers, but headers are really just a hack.
  • C# / Python have a great object model, but don't separate interface from implementation.

Another great thing was the amazing GUI designer and visual component system. Not even Visual Basic / Visual Studio came close to it...

I wouldn't use Delphi in a serious project anymore though. It's just not widely used enough, and there are much nicer languages like C#, Python, and even modern C++11.


Returning to the game itself, here's some of the neat features my engine had:

  • A particle system engine (defined by INI files) - see the waterfall in the loading menu
  • A Voxel model loader & renderer, specifically to load voxel models from Tiberian Sun / RA2.
    I believe this was adapted from an open-source voxel-viewing program also written in Delphi.
  • A proprietary image / model encoding (I don't know why I did this)
  • A Blender extension to export models to my proprietary format
  • The GUI was defined by the native Delphi 7 GUI editor, but rendered in OpenGL with custom textures

It also had a map editor: (basically a simple height-map + texture editor)

Unfortunately I never implemented multiplayer or a decent collsion-detection system, so this isn't useful for anything except as a bit of history.

View Comments...

A while back I reverse-engineered the Outback MATE protocol and made a Python library for emulating a MATE, and set it up collecting data from the family Holiday House (which is lucky enough to have an internet connection!). For a while I didn't do anything more, and just left it collecting data, until I recently stumbled upon a nice open-source project called Grafana.

Grafana is a webserver written in Go which provides a beautiful UI for presenting and exploring time-series data. It seemed a natural fit to the solar charger data I had been collecting!

Here's a screenshot of the system in action:
(I haven't made the dashboard available publically because of performance issues)

Now the effort of reverse-engineering the Outback protocol has finally paid off!

Look at all the insights we have into the system!
You can see how much energy went into the system each day, how long the batteries keep their charge, how much the batteries have been drained (we rent the holiday house out to the public so this is a big concern), and lots of other useful info!

You can even drill right down and see the Outback MX 60/80's charging algorithm:

Pretty cool huh?

The Set-up

Not getting any solar power today!Not getting any solar power today!

The holiday house is located in the remote New Zealand alps, far away from power and civilisation, though we are lucky to have an always-on WiFi internet connection. It is equipped with a bank of Solar panels and a bank of 24V lead-acid batteries, regulated by an Outback FLEXMax 60/80 charge controller. (It also has a wind turbine attached for charging, but this isn't monitored)

Hardware

At the house, I set up a low-power MIPS linux board (The Carambola2), connected to the MX charger through a USB<>TTL serial adapter and my opto-isolator circuit. The board is powered directly from the 24V battery bank (through a buck regulator) so it can stay on 24/7.

The reason I chose this as opposed to a Raspberry Pi is because it is actually a router and WiFi access point, while also providing GPIOs and UART for monitoring the house. It's not as powerful as a RPi (it uses a MIPS core rather than the more common ARM), but it's powerful enough for some basic data collection!

Collection

I haven't really put in a solid system for data collection yet.

It consists of some pretty basic Python scripts, one at the holiday house which collects the data using my pyMATE library and uploads it to a server, and the other sits on the server collecting data and stores it into a Postgres database.

I plan on improving this in the future to make it more reliable and use less internet data, once I find a suitable open-source project (or I might end up making my own!)

Grafana

It's refreshing to finally see an application not written in Node.JS (I totally don't have anything against Node.JS *cough*). Being written in Go it is fast and snappy, and light on resources! I keep it running in a cheap Linux virtual machine hosted on Azure, along with the Postgres database.

Unfortunately by default Grafana only supports time-series databases (TSDBs), not regular SQL databases like Postgres, which is where all my data is. I found someone's Github fork which adds SQL support, and through that was able to connect my Postgres DB with very little effort.

I'll probably consider moving to a TSDB in the future though, because querying Postgres isn't particularly fast.

View Comments...