Dieses Projekt beschreibt sowohl die Kommunikation zwischen einem Arduino Mega und einem UPNP fähigen Router, als auch die serielle Kommunikation zwischen Gameboy und Arduino. Es handelt sich hierbei um einen Beitrag für den "Pimp your Fritz!"-Wettbewerb der Maker Faire 2015 in Berlin. Die Teilnahmebedingungen befinden sich hier. Die finalisten befinden sich auf der Seite von AVM. Die Gewinner bei Heise.

Foto (c) AVM

In der CT Make 1/2016 gibt es einen kurzen Artikel über den FritzBoy.

 

Benötigte Bauteile:
# Bezeichnung ~Preis
1 Gameboy (DMG) oder Gameboy Color 30 €
1 USB 64m Smart card (z.B. von hier) 50 €
1 Gameboy Link Kabel 5 €
1 Arduino Mega 15 €
1 Arduino Ethernet Shield 10 €
1 Gehäuse (Optional) 5 €
    ~100 €

 

Nachdem der Arduino Mega Mikrocontroller eine IP-Adresse von der Fritz!Box erhalten hat, sendet er einen SOAP-Request an sein Default-Gateway. In dieser Anfrage erfragt er die Eigenschaften des WAN-Interfaces und erhält die maximale Up- und Downloadbandbreite („NewLayer1UpstreamMaxBitRate“ und „NewLayer1DownstreamMaxBitRate“) zurück. Als nächstes fragt er periodisch, alle drei Sekunden, die aktuelle Bandbreitenauslastung ab („NewByteReceiveRate“ und „NewByteSendRate“). Die gesammelten Werte werden in Megabit umgerechnet und jede Sekunde über die serielle Schnittstelle an den Gameboy übertragen. Auf der Cartridge des Gameboys läuft ein Programm, welches auf der seriellen Schnittstelle lauscht und die letzten 50 empfangenen Werte auf einer Skala anzeigt.

Abgesehen vom Anlöten des Link-Kabels muss keine zusätzliche Hardware gebaut werden. Der Aufbau sieht wie folgt aus:

Hier noch ein Foto des Arduino Megas mit dem Ethernet Shield:

Nach dem Start des Gameboys kommt als Erstes der Splash-Screen:

Der Gameboy wartet dann auf serielle Signale:

Wenn diese empfangen werden, werden sie in einem Graphen angezeigt:

 

Hier der Code für den Gameboy. Das Übertragungsprotokoll sieht folgendermaßen aus:

Es werden immer 7 Byte übertragen, das ist zwar ineffizient, aber simpel:

Byte Bedeutung Gültige Werte Beispiel
0 Aktueller relativer Downstream auf einer Skala von 0-50 0-50 30 / 50
1 Aktueller relativer Upstream auf einer Skala von 0-50 0-50 3 / 50
2 Absoluter aktueller Downstream 0-254 44 Mbit/s
3 Absoluter aktueller Upstream 0-254 5 Mbit/s
4 Maximaler Downstream 0-254 50 Mbit/s
5 Maximaler Upstream 0-254 10 Mbit/s
6 [End of Stream] 255 255

Hinweis: Es handelt sich um unsignierte Bytes (UBYTE). Das sechste Byte gibt an, dass die Übertragung abgeschlossen wurde.

#include <gb/gb.h>
#include <stdio.h>
#include <gb/drawing.h>
#include <rand.h>

unsigned char tile_fritzbox[] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08,
  0x11, 0x10, 0x23, 0x20, 0x47, 0x40, 0x6E, 0x61,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F,
  0x10, 0x10, 0x20, 0x20, 0x40, 0x41, 0x8C, 0x80,
  0x1E, 0x00, 0x3F, 0x00, 0x7F, 0x00, 0xFF, 0x00,
  0xFF, 0x00, 0xBF, 0x40, 0x7F, 0x80, 0xEF, 0x10,
  0x3D, 0x32, 0x1F, 0x18, 0x0F, 0x0C, 0x07, 0x06,
  0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xDF, 0x20, 0xBB, 0x44, 0x77, 0x88, 0xEE, 0x11,
  0xDD, 0x22, 0xFB, 0x84, 0xF7, 0xC8, 0x7E, 0x60,
  0x3C, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x06, 0x06,
  0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x90,
  0x08, 0x08, 0x04, 0x24, 0x82, 0x12, 0xC1, 0x01,
  0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x00, 0xFC, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x20, 0x20, 0x50, 0x70, 0x50, 0x70, 0x50, 0x70,
  0x50, 0x70, 0x50, 0x70, 0x50, 0x70, 0x50, 0x70,
  0xD0, 0xF0, 0x50, 0x70, 0x30, 0x30, 0x10, 0x10,
  0xFC, 0x00, 0xF8, 0x00, 0xF0, 0x00, 0xE0, 0x00,
  0xC0, 0x00, 0x81, 0x01, 0x03, 0x02, 0x07, 0x04,
  0x0F, 0x09, 0x1F, 0x13, 0x3E, 0x26, 0x7C, 0x4C,
  0xF8, 0x98, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00,
  0x08, 0x08, 0x1C, 0x1C, 0x3C, 0x24, 0x7C, 0x4C,
  0xF8, 0x98, 0xF0, 0x30, 0xE0, 0x60, 0xC0, 0xC0,
  0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00,
  0x7F, 0x00, 0x70, 0x0F, 0x70, 0x08, 0x70, 0x08,
  0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x70, 0x0F,
  0x70, 0x08, 0x70, 0x08, 0x70, 0x08, 0x00, 0x38,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
  0x1C, 0x80, 0x7F, 0x80, 0x73, 0x08, 0x73, 0x08,
  0x73, 0x08, 0x7F, 0x80, 0x7E, 0x81, 0x7C, 0x82,
  0x7C, 0x00, 0x76, 0x08, 0x77, 0x08, 0x77, 0x08,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x73, 0x08, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x38, 0x00, 0x18, 0x00, 0x38, 0x04,
  0x3B, 0x04, 0x3B, 0x04, 0xBB, 0x04, 0xB8, 0x45,
  0xB8, 0x44, 0x38, 0x84, 0x38, 0x04, 0x38, 0x04,
  0x38, 0x04, 0x38, 0x04, 0x00, 0x9C, 0x80, 0x40,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0x70, 0x8F,
  0x70, 0x08, 0x70, 0x08, 0x70, 0x08, 0x70, 0x08,
  0x70, 0x08, 0x70, 0x08, 0x70, 0x08, 0x70, 0x08,
  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x70, 0x08, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
  0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x03, 0x00, 0x07, 0x00, 0x0E, 0x01, 0x1C, 0x03,
  0x3F, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0x00, 0x7F,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00,
  0xF8, 0x00, 0xF0, 0x0C, 0xE0, 0x18, 0xC0, 0x30,
  0x80, 0x60, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,
  0xFC, 0x00, 0xFC, 0x02, 0xFC, 0x02, 0x00, 0xFE,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE3,
  0x42, 0xA2, 0x42, 0xA2, 0x42, 0xA2, 0x42, 0xA2,
  0x43, 0xA3, 0x42, 0xA2, 0x02, 0xE2, 0x02, 0x02,
  0x02, 0x42, 0x42, 0xA2, 0x03, 0x43, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xC1,
  0x22, 0x22, 0x24, 0x24, 0x24, 0x24, 0x44, 0x44,
  0xF4, 0xF4, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
  0x14, 0x14, 0x22, 0x22, 0xC1, 0xC1, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xC4,
  0x22, 0x22, 0x11, 0x11, 0x10, 0x10, 0x10, 0x10,
  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
  0x10, 0x10, 0x20, 0x20, 0xC0, 0xC0, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04,
  0x08, 0x08, 0x10, 0x10, 0xA0, 0xA0, 0x40, 0x40,
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88,
  0x88, 0x88, 0xA8, 0xA8, 0xF8, 0xF8, 0xD8, 0xD8,
  0x00, 0x00, 0x18, 0x18, 0x20, 0x20, 0x20, 0x20,
  0x79, 0x79, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x47, 0x47, 0x89, 0x89, 0x09, 0x09, 0x07, 0x07,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x06, 0x06, 0x09, 0x09, 0x09, 0x09, 0x87, 0x87,
  0x01, 0x01, 0x0F, 0x0F, 0x19, 0x19, 0x13, 0x13,
  0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x12, 0x12,
  0x72, 0x72, 0x92, 0x92, 0x92, 0x92, 0x71, 0x71,
  0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x41, 0x41,
  0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x89, 0x89,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3,
  0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x23,
  0x78, 0x78, 0x44, 0x44, 0x04, 0x04, 0x18, 0x18,
  0x20, 0x20, 0x60, 0x60, 0x42, 0x42, 0x7C, 0x7C,
  0x3C, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x3C,
  0x08, 0x08, 0x18, 0x18, 0x28, 0x28, 0x48, 0x48,
  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  0x7E, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x3C, 0x3C,
  0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x78, 0x78,
  0x66, 0x66, 0x7E, 0x7E, 0x5A, 0x5A, 0x5A, 0x5A,
  0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C,
  0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x3E, 0x3E,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x53,
  0x64, 0x64, 0x44, 0x44, 0x44, 0x44, 0x43, 0x43,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38,
  0x44, 0x44, 0x7C, 0x7C, 0x40, 0x40, 0x3C, 0x3C,
  0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
  0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x7C, 0x7C, 0x92, 0x92, 0x92, 0x92, 0x82, 0x82,
  0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00,
  0x46, 0x46, 0x49, 0x49, 0x49, 0x49, 0x47, 0x47,
  0x01, 0x01, 0x0F, 0x0F, 0x19, 0x19, 0x13, 0x13,
  0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  0x87, 0x87, 0x89, 0x89, 0x89, 0x89, 0x27, 0x27,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
  0x48, 0x48, 0x70, 0x70, 0x40, 0x40, 0x38, 0x38,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88,
  0x88, 0x88, 0xA8, 0xA8, 0xF8, 0xF8, 0xD9, 0xD9,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

unsigned char map_fritzbox[] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x12, 0x18, 0x1A, 0x20,
  0x22, 0x28, 0x2A, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x13, 0x19, 0x1B, 0x21,
  0x23, 0x29, 0x2B, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x1C, 0x1E, 0x25,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
  0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03,
  0x09, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06,
  0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x07,
  0x0D, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x3D, 0x3E, 0x3F, 0x40, 0x00, 0x41,
  0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x4B, 0x35, 0x36, 0x37,
  0x39, 0x3A, 0x3B, 0x3C, 0x49, 0x4A, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x38,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

int main ()
{
  UINT8 DEBUG = 0;
  UINT8 YPOSITION = 72;
  UINT8 GRAPHWIDTHFULL = 100;
  UINT8 GRAPHWIDTHHALF = 50;
  UBYTE max_downstream = 0;
  UBYTE max_upstream = 0;
  UBYTE current_downstream = 0;
  UBYTE current_upstream = 0;
  UINT8 XOFFSET = 30;
  UBYTE array_downstream[50]; // array for downstream values
  UBYTE array_upstream[50]; // array for upstream values
  UBYTE buffer[7]; // buffer for incoming transfer
  UBYTE i, n = 0;
  UBYTE random;
  UBYTE *s;
  UINT8 c; // For
  UINT8 position;
  UINT8 TMP = 2;
  UINT8 demomode = 0; 
  UINT8 packetreceived = 0;
  
  // Show welcome screen
  set_bkg_data(0, 127, tile_fritzbox);
  set_bkg_tiles(0, 0, 20, 18, map_fritzbox);
  SHOW_BKG;
  DISPLAY_ON;
  for (c = 0; c != 100; c++) {
    delay(40);
    if (joypad() != 0)
      break;
  }

  // Initialize arrays
  for (c = 0; c < GRAPHWIDTHHALF; c++) {
    array_downstream[c] = 0;
    array_upstream[c] = 0;
  }
  for (c = 0; c < 8; c++) {
    buffer[c] = 0;
  }

  // Initialize random
  initarand(0x5F);

  // Draw a box
  color(LTGREY, WHITE, SOLID);
  box(XOFFSET - 1, YPOSITION - 52, XOFFSET + GRAPHWIDTHFULL - 1, YPOSITION + 52, M_NOFILL);

  // Draw a line in the middle
  color(BLACK, WHITE, SOLID);
  line(XOFFSET, YPOSITION, XOFFSET + GRAPHWIDTHFULL - 1, YPOSITION);

  // Write text
  gotogxy(1, 1);
  gprintf("Down:");

  gotogxy(1, 16);
  gprintf("Up:");

  while (1) {
    // Plot the values
    position = 1;
    for (c = 1; c < GRAPHWIDTHHALF; c++) {

      // Generate downstream values
      if (c == 0 || array_downstream[c] == array_downstream[c - 1])
      {
        // Do nothing
        ;
      } else if (array_downstream[c] > array_downstream[c - 1])
      { // New value is higher than the old one --> generate line
        color(DKGREY, WHITE, SOLID);
        line(XOFFSET + position, YPOSITION - 1, XOFFSET + position, (YPOSITION - 1) - array_downstream[c]);
      } else {
        // Erase the rest of the line for downstream
        color(WHITE, WHITE, SOLID);
        line(XOFFSET + position, (YPOSITION - 1) - array_downstream[c], XOFFSET + position, YPOSITION - 51);
      }

      // Generate upstream values
      if (c == 0 || array_upstream[c] > array_upstream[c - 1])
      { // New value is higher than the old one --> generate line
        color(LTGREY, WHITE, SOLID);
        line(XOFFSET + position, YPOSITION + 1, XOFFSET + position, (YPOSITION + 1) + array_upstream[c]);
      } else { // Erase the rest of the line for upstream
        color(WHITE, WHITE, SOLID);
        line(XOFFSET + position, YPOSITION + 1 + array_upstream[c], XOFFSET + position, YPOSITION + 51);
      }

      // Generate point
      color(BLACK, WHITE, SOLID);
      plot_point(XOFFSET + position, YPOSITION - 1 - array_downstream[c]);
      plot_point(XOFFSET + position, YPOSITION + 1 + array_upstream[c]);
      position += 2;
    }

    // Set color to black for text
    color(BLACK, WHITE, SOLID);

    // Shift complete array to the left
    for (c = 0; c < GRAPHWIDTHHALF - 1; c++) {
      array_downstream[c] = array_downstream[c + 1];
      array_upstream[c] = array_upstream[c + 1];
    }

    // print current text-values downstream...
	if(packetreceived == 1){
		gotogxy(6, 1);
		if (current_downstream == 0)
		gprintf("<1 ", current_downstream);
		else
		gprintf("%u ", current_downstream);
		gprintf("/ %u Mbit  ", max_downstream);
		
		// ... and upstream
		gotogxy(6, 16);
		if (current_upstream == 0)
		gprintf("<1 ", current_upstream);
		else
		gprintf("%u ", current_upstream);
		gprintf("/ %u Mbit  ", max_upstream);
	} else {
		color(DKGREY, WHITE, SOLID);
		gotogxy(5, 4);
		gprintf("connecting");
		gotogxy(9, 5);
		gprintf("to");
		gotogxy(5, 6);
		gprintf("Fritz!Boy");
		gotogxy(9, 7);
		
		color(LTGREY, WHITE, SOLID);
		gotogxy(8, 11);
		gprintf("hold");
		gotogxy(6, 12);
		gprintf("\"SELECT\"");
		gotogxy(6, 13);
		gprintf("for demo");
	}

    // Receive new values from
    gotogxy(16, 16);
    s = buffer;

    if (DEBUG == 1) { // Debug the incoming values
      gotogxy(1, TMP);
      TMP++;
      TMP = TMP % 14;
      gprintf("IN:");
    }

    while (1) {
      receive_byte();
      /* Wait for IO completion... */
      while (_io_status == IO_RECEIVING) {
		if(joypad() == J_SELECT) {
			demomode = 1;
			break;
		}
	  }

	// Break the outer loop
    if(demomode == 1)
		break;
	     
      if (_io_status != IO_IDLE) { // Error
        if (DEBUG == 1){
			gotogxy(1, 5);
			gprintf("IO:%u", _io_status);
		}
        break;
      }

      if (DEBUG == 1)
        gprintf("%u", _io_in);

      *s = _io_in;
      if (*s == 255) {
        //if (_io_in == 255){
        // gprintf("X");
        break;
      }
      s++;
	}
	
	
	
    if (_io_status == IO_IDLE || demomode) {
		
		if(packetreceived == 0){ // First packet received
			// Clear the text
			color(WHITE, WHITE, SOLID);
			box(XOFFSET + 3, YPOSITION - 49, XOFFSET + GRAPHWIDTHFULL - 5, YPOSITION - 2, M_FILL);
			box(XOFFSET + 3, YPOSITION + 49, XOFFSET + GRAPHWIDTHFULL - 5, YPOSITION + 2, M_FILL);
			packetreceived = 1; // Hide the text
		}
				
		// current graph
		if(demomode){ // Demo = random
			random = rand();
			random = random % 50; // current downstream percent 0-49
			buffer[0] = random;
			random = rand();
			random = random % 50; // current downstream percent 0-49
			buffer[1] = random;
			buffer[2] = buffer[0];
			buffer[3] = buffer[1] / 10;
			buffer[4] = 100;
			buffer[5] = 10;
		
			demomode = 0;
		}
	
		array_downstream[GRAPHWIDTHHALF - 1] = buffer[0];
		array_upstream[GRAPHWIDTHHALF - 1] = buffer[1];
		current_downstream = buffer[2];
		current_upstream = buffer[3];
		max_downstream = buffer[4];
		max_upstream = buffer[5];
	
	  if(DEBUG == 1){
		gotogxy(1, 5);
		gprintf("cDp%u", buffer[0]);
		gotogxy(1, 6);
		gprintf("cUp%u", buffer[1]);
		
		gotogxy(1, 7);
		gprintf("cDa%u", buffer[2]);
		gotogxy(1, 8);
		gprintf("cUa%u", buffer[3]);
		
		gotogxy(1, 9);
		gprintf("U%u", max_upstream);
		gotogxy(1, 10);
		gprintf("D%u", max_downstream);
		}
    }
  }
  return 0;
}

Er kann mit GBDK kompilliert werden. Das bekommt ihr hier. Die Tiles können mit dem Gameboy Tile Designer und dem Gameboy Map Builder bearbeitet werden. Auch wenn es seit 16 Jahren kein Update mehr gab, läuft die Software noch problemlos unter Windows 10. Herunterladen könnt ihr sie hier. Falls ihr keine Lust habt, das ROM selber zu kompillieren, könnt ihr euch die fritzboy.gb Datei hier herunterladen. Sie muss einfach mittels des GB-USB Programms auf die programmierbare Cartridge übertragen werden.

Für die Kommunikation mit dem Gameboy sind die Funktionen in der "_gameboy.ino" zuständig (Quelle tomvdb):

/*
 * FritzBoy Request-Client
 * Send messages to Gameboy
*/

boolean pushValues() {
  // Send current values to gameboy
  if (maximum_downstream_short != UNDEFINED && maximum_upstream_short != UNDEFINED && rate_receive_percent != UNDEFINED && rate_send_percent != UNDEFINED) {
    Serial.print("Sending maximum and current bandwidth curDown%/CurUp% | curDownA/curUpA | maxDown/maxUp: ");
    Serial.print(rate_receive_percent);
    Serial.print("/");
    Serial.print(rate_send_percent);
    Serial.print(" | ");
    temp_a = rate_receive_abs / 1000000;
    Serial.print(temp_a);
    Serial.print("/");
    temp_b = rate_send_abs / 1000000;
    Serial.print(temp_b);
    Serial.print(" | ");
    Serial.print(maximum_downstream_short);
    Serial.print("/");
    Serial.println(maximum_upstream_short);

    sendValuesToGB(rate_receive_percent, rate_send_percent, temp_a, temp_b, maximum_downstream_short, maximum_upstream_short);
    return true;
  }
  return false;
}

// Format: [DOWNSTREAM-GRAPH][UPSTREAM-GRAPH][DOWNSTREAM-ABSOLUTE][UPSTREAM-ABSOLUTE][DOWNSTREAM-MAXIMUM][UPSTREAM-MAXIMUM]
void sendValuesToGB(byte downstream_percent, byte upstream_percent, byte downstream_absolute, byte upstream_absolute, byte maximum_downstream_short, byte maximum_upstream_short) {
  // i.e. "123456";
  outbuffer[0] = downstream_percent;
  outbuffer[1] = upstream_percent;
  outbuffer[2] = downstream_absolute;
  outbuffer[3] = upstream_absolute;
  outbuffer[4] = maximum_downstream_short;
  outbuffer[5] = maximum_upstream_short;
  sendBytesToGB(outbuffer, 6);
  delay(400);
}

// Converts the values to a bytestream and sends it
void sendBytesToGB(byte* out, int out_length) {
  Serial.print("Sending:");

  for (int i = 0; i < out_length; i++) {
    Serial.print(out[i]);
    Serial.print('-');
    byte dataToSend = out[i];
    if (dataToSend == 255) // End-byte!
      dataToSend = 254;
    sendByte(dataToSend);
    delay(DELAYBETWEENBITS);
  }

  // Send end-byte
  sendByte(255);
  Serial.println("E");
  delay(DELAYBETWEENBITS);
  digitalWrite(PIN_LED, LOW);
}

// Send a single byte
void sendByte(byte out) {
  for (byte counter = 0; counter < 8; counter++ )
  {
    if ( out & 0x80 ) { // Logical 1
      digitalWrite(PIN_LED, HIGH);
      digitalWrite(PIN_SO, HIGH );
      digitalWrite(PIN_CLOCK, LOW );
      delayMicroseconds(DELAYBETWEENBITS);
      digitalWrite(PIN_CLOCK, HIGH );
      delayMicroseconds(DELAYBETWEENBITS);
    } else { // Logical 0
      digitalWrite(PIN_LED, LOW);
      digitalWrite(PIN_SO, LOW );
      digitalWrite(PIN_CLOCK, LOW );
      delayMicroseconds(DELAYBETWEENBITS);
      digitalWrite( PIN_CLOCK, HIGH );
      delayMicroseconds(DELAYBETWEENBITS);
    }
    out = out << 1; // Next bit
  }
}

In der "_sender.ino" wird die UPNP Abfrage (ein HTTP Soap request) erstellt und an das default Gateway (= der Router) verschickt:

/*
 * FritzBoy Request-Client
 * Sender: Sends SOAP-requests to the router
*/

// Maximum bandwidth usage
const String soapAction_GetCommonLinkProperties = "SoapAction:urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1#GetCommonLinkProperties";
const String soapU_GetCommonLinkProperties  = "<u:GetCommonLinkProperties xmlns:u=urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 />";

// Current bandwidth usage
const String soapAction_GetAddonInfos = "SoapAction:urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1#GetAddonInfos";
const String soapU_GetAddonInfos = "<u:GetAddonInfos xmlns:u=urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 />";

boolean sendRequest_maximumbandwidth() {
  return sendRequest(soapAction_GetCommonLinkProperties, soapU_GetCommonLinkProperties);
}

boolean sendRequest_bandwidthusage() {
  return sendRequest(soapAction_GetAddonInfos, soapU_GetAddonInfos);
}

boolean sendRequest(String soapAction, String soapU) {
  Serial.println("Sending request to router");

  rate_receive_abs = UNDEFINED;
  rate_send_abs = UNDEFINED;

  // if you get a connection, report back via serial:
  if (client.connect(Ethernet.gatewayIP(), 49000)) {

    Serial.println("Sending POST request");
    request = "POST /igdupnp/control/WANCommonIFC1 HTTP/1.1\r\n";
    request += "HOST: ";
    request += router_ip;
    request += ":49000\r\n";
    //client.print(Ethernet.gatewayIP());
    request += "User-Agent: fritzboy\r\n";
    request += "Accept: */*\r\n";
    request += "Content-Type: text/xml; charset=utf-8\r\n";
    request += soapAction;
    request += "\r\n";
    // Serial.print(request);
    client.print(request);
    delay(SENDING_DELAY);
    request = "Content-Length: ";
    String xmldata1 = "<?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>\r\n<s:Body> ";
    // ... soapU ...
    String xmldata3 = " </s:Body> </s:Envelope>\r\n\r\n";
    int contentlength = xmldata1.length() + soapU.length() + xmldata3.length();
    request += contentlength;
    request += "\r\n\r\n";

    // Serial.print(request);
    client.print(request);
    delay(SENDING_DELAY);
    // Serial.print(xmldata1);
    client.print(xmldata1);
    delay(SENDING_DELAY);
    // Serial.print(soapU);
    client.print(soapU);
    delay(SENDING_DELAY);
    // Serial.print(xmldata3);
    client.print(xmldata3);
    delay(SENDING_DELAY);
    client.flush();
    delay(SENDING_DELAY);
    Serial.println("Post request sent");
    return true;
  }
  else {
    Serial.println("connection failed");
    return false;
  }
}

Die Antwort wird dann in den Funktionen der "_handler.ino" geparsed:

/*
 * FritzBoy Request-Client
 * Handler: Handles resonses from the router
*/

boolean handle_response()
{
  // Parse response for maximum upstream rate
  if (maximum_upstream_long == UNDEFINED) {
    if (strstr(response, "</NewLayer1UpstreamMaxBitRate") != NULL) {
      Serial.print("//Found maximum upstream//");
      pch = strrchr(response, '<');
      lastIntegerPosition = pch - response - 1;
      pch = strrchr(response, '>');
      firstIntegerPosition = pch - response + 1;

      if (lastIntegerPosition - firstIntegerPosition == 0)
        rate_receive_abs = 0;
      else {
        char subbuff[lastIntegerPosition - firstIntegerPosition + 2];
        memcpy(subbuff, &response[firstIntegerPosition], lastIntegerPosition - firstIntegerPosition + 1);
        subbuff[lastIntegerPosition - firstIntegerPosition + 1] = '\0';

        maximum_upstream_long = atol(subbuff);
        if (maximum_upstream_long == UNDEFINED) // Unsigned long
          maximum_upstream_long++;
        maximum_upstream_short = maximum_upstream_long / 1000000;

        Serial.print("Maximum upstream:");
        Serial.println(maximum_upstream_short);
      }
    }
  }

  // Parse response for maximum upstream rate
  if (maximum_downstream_long == UNDEFINED) {
    if (strstr(response, "</NewLayer1DownstreamMaxBitRate") != NULL) {
      Serial.print("//Found maximum downstream//");

      pch = strrchr(response, '<');
      lastIntegerPosition = pch - response - 1;
      pch = strrchr(response, '>');
      firstIntegerPosition = pch - response + 1;

      if (lastIntegerPosition - firstIntegerPosition == 0)
        rate_receive_abs = 0;
      else {
        char subbuff[lastIntegerPosition - firstIntegerPosition + 2];
        memcpy(subbuff, &response[firstIntegerPosition], lastIntegerPosition - firstIntegerPosition + 1);
        subbuff[lastIntegerPosition - firstIntegerPosition + 1] = '\0';

        maximum_downstream_long = atol(subbuff);
        if (maximum_downstream_long == UNDEFINED) // Unsigned long
          maximum_downstream_long++;
        maximum_downstream_short = maximum_downstream_long / 1000000;

        Serial.print("Maximum downstream:");
        Serial.println(maximum_downstream_short);
      }
    }
  }

  // Parse response for receive rate
  if (!response_found_downstream) {
    if (strstr(response, "</NewByteReceiveRate") != NULL) {
      Serial.print("//Found current receive//");

      pch = strrchr(response, '<');
      lastIntegerPosition = pch - response - 1;
      pch = strrchr(response, '>');
      firstIntegerPosition = pch - response + 1;

      if (lastIntegerPosition - firstIntegerPosition == 0)
        rate_receive_abs = 0;
      else {
        char subbuff[lastIntegerPosition - firstIntegerPosition + 2];
        memcpy(subbuff, &response[firstIntegerPosition], lastIntegerPosition - firstIntegerPosition + 1);
        subbuff[lastIntegerPosition - firstIntegerPosition + 1] = '\0';

        rate_receive_abs = atol(subbuff);
        if (rate_receive_abs == UNDEFINED) // Unsigned long
          rate_receive_abs++;
        rate_receive_abs = rate_receive_abs;

        Serial.print("rate_receive_abs (byte/bits):");
        Serial.print(rate_receive_abs);
        Serial.print('/');
        rate_receive_abs = rate_receive_abs * 8; // Convert byte to bit
        Serial.println(rate_receive_abs);

        temp = (unsigned long) rate_receive_abs * (unsigned long) 50;
        rate_receive_percent = temp / maximum_downstream_long;
        if (rate_receive_percent > 49) // catch Maximum
          rate_receive_percent = 49;

        Serial.print("receiverate abs/percent:");
        Serial.print(rate_receive_abs);
        Serial.print('/');
        Serial.println(rate_receive_percent);

      }
      response_found_downstream = true;
    }
  }

  // Parse response for send rate
  if (!response_found_upstream) {
    if (strstr(response, "</NewByteSendRate") != NULL) {
      Serial.print("//Found current send//");
      pch = strrchr(response, '<');
      lastIntegerPosition = pch - response - 1;
      pch = strrchr(response, '>');
      firstIntegerPosition = pch - response + 1;

      if (lastIntegerPosition - firstIntegerPosition == 0)
        rate_send_abs = 0;
      else
      {
        char subbuff[lastIntegerPosition - firstIntegerPosition + 2];
        memcpy(subbuff, &response[firstIntegerPosition], lastIntegerPosition - firstIntegerPosition + 1);
        subbuff[lastIntegerPosition - firstIntegerPosition + 1] = '\0';
        // Serial.print("Delta:");
        // Serial.println(subbuff);

        rate_send_abs = atol(subbuff);
        if (rate_send_abs == UNDEFINED) // Unsigned long
          rate_send_abs++;
        rate_send_abs = rate_send_abs;

        Serial.print("rate_send_abs (byte/bits):");
        Serial.print(rate_send_abs);
        Serial.print('/');
        rate_send_abs = rate_send_abs * 8; // Convert byte to bit
        Serial.println(rate_send_abs);

        // highest_downstream = max(highest_downstream, rate_receive_abs);
        // Serial.print("highest_downstream:");
        // Serial.println(highest_downstream);
        // unsigned long temp = (long) rate_receive_abs * (long) 50;
        // rate_receive_percent = temp / highest_downstream;
        temp = (unsigned long) rate_send_abs * (unsigned long) 50;
        rate_send_percent = temp / maximum_upstream_long;
        if (rate_send_percent > 49) // catch Maximum
          rate_send_percent = 49;

        Serial.print("sendrate abs/percent:");
        Serial.print(rate_send_abs);
        Serial.print('/');
        Serial.println(rate_send_percent);
      }
      response_found_upstream = true;
    }
  }

  if (response_found_downstream && response_found_upstream)
    return true;
  else
    return false;
}

 

Das gesamte Repository gibt es hier.

Letzlich muss nur noch das Link-Kabel durchtrennt und folgendermaßen angeschlossen werden (Die Abbildung stellt das Kabel dar!):

SOUT (Rot) --> Arduino PIN 36
SCK (Grün) --> Arduino PIN 38
GND (Schwarz) --> Masse
SIN wird nicht benötigt, da keine Kommunikation vom Gameboy zum Arduino stattfindet.

Kommentare  

#1 Sember 2015-12-01 07:15
Hallo,
das Projekt ist echt super und es hat mich animiert das ganze nachzubauen (allerdings ohne Gameboy). Wenn ich das Skript laufen lasse kommt bei mir über den seriellen Monitor allerdings ein Fehler? (Eingesetzt in das Skript habe ich meine RouterIP, ansonsten ist es so wie es hier steht belassen, in der fritzbox 7330 ist "Statusinformat ion über UpnP übertragen" an):

Fritz!Boy 1.0 starting, waiting for DHCP
IP: 192.168.1.63
GW: 192.168.1.1
Sending request to router
Sending POST request
Post request sent
HTTP/1.1 404 Not Found
Connection: close
Content-Length: 174
Content-Type: text/html

404 Not Found (ERR_NOT_FOUND) 404 Not FoundERR_NOT_FO UNDWebserver Tue, 01 Dec 2015 07:02:11 GMT
Sending request to router
connection failed
#2 Marcel I. 2015-12-01 07:34
Hallo Sember,

Fehler 404 lässt darauf schließen, dass die entsprechende Website nicht erreichbar ist. Ich vermute daher, dass sich deine Firmware von meiner unterscheidet.

Bitte stelle sicher, dass du die aktuellste Firmware auf der Fritzbox hast. Falls das nicht klappt, vermute ich, dass die URLs bei deiner Box andere sind.

grüße
Marcel