--- /dev/null
+LED Wall Bits n Bobs
+
+There is a client/server relationship between the two scripts. I have a box monitoring all my network traffic at 10Gbps. The Perl sniffer script listens on this host and that interface (sniffer.pl) and sends UDP packets to the the RaspberryPi that has a Python script listening on a UDP port and switches on/off the pixels.
+
+Bill of Materials:
+1. Four LED Grids - https://www.amazon.com/gp/product/B01DC0IOCK/
+2. One Power Supply - https://www.amazon.com/gp/product/B01B1QKLNW
+3. One RaspberryPi 3 and relavent bits to make it work
+4. Some wire and mediocre soldering skills
+
+Install Instructions:
+1. Connect/Solder up the panel's INPUTS/OUTPUTs, and extend the voltage injection. It's pretty darn simple.
+2. Install Raspbian
+3. Install rpi_ws281x on the RaspberryPi : https://github.com/jgarff/rpi_ws281x
+4. Install any missing Python libs via pip
+5. On the sniffer box, use CPAN to install all the required libs
+6. Change the hostnames/IP, subnet filter range, and ethernet interface to sniff from
+
+Start the scripts:
+
+sudo python server.py
+./sniffer.pl
+
+
+*Potenial bugs*
+1. I'm not entirely convinced the timeout to clear a pixel is making its way over. Might have to make a double check in the Python as well
--- /dev/null
+import socket
+import threading
+import time
+from neopixel import *
+
+LED_COUNT = 1024 # Number of LED pixels.
+LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
+#LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
+LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
+LED_DMA = 10 # DMA channel to use for generating signal (try 10)
+LED_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest
+LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
+LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
+
+bind_ip = '0.0.0.0'
+bind_port = 10000
+strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
+strip.begin()
+
+server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+server.bind((bind_ip, bind_port))
+
+print 'Listening on {}:{}'.format(bind_ip, bind_port)
+
+pixels = []
+for i in range(1024):
+ pixels.append(tuple((0,0,0)))
+
+strip.show()
+
+print "Starting Server"
+while True:
+ data, addr = server.recvfrom(1024)
+ if data:
+ #print 'Received {}'.format(data)
+ elements=format(data).split(",")
+ color=elements[0].split(":")
+ pixel_color=pixels[int(color[1])]
+ red=pixel_color[0]
+ green=pixel_color[1]
+ blue=pixel_color[2]
+ if (int(elements[1])==0):
+ strip.setPixelColor(int(color[1]), Color(0,0,0))
+ if color[0]=="R":
+ strip.setPixelColor(int(color[1]), Color(green, int(elements[1]), blue))
+ pixels[int(color[1])] =(int(elements[1]),green,blue)
+ if color[0]=="G":
+ strip.setPixelColor(int(color[1]), Color(int(elements[1]), red, blue))
+ pixels[int(color[1])] =(red,int(elements[1]),blue)
+ if color[0]=="B":
+ strip.setPixelColor(int(color[1]), Color(green, red, int(elements[1])))
+ pixels[int(color[1])] =(red,green,int(elements[1]))
+ strip.show()
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use POSIX;
+use Net::Pcap;
+use NetPacket::Ethernet;
+use NetPacket::IP;
+use NetPacket::TCP;
+use NetPacket::UDP;
+use Socket;
+use IO::Socket;
+
+my $server = IO::Socket::INET->new(
+ Proto => 'udp',
+ PeerPort => 10000,
+ PeerAddr => 'led-wall' )
+or die "can't setup server";
+
+my @led_timer;
+
+my $err;
+
+my $dev = "eth1";
+unless (defined $dev) {
+ $dev = Net::Pcap::lookupdev(\$err);
+ if (defined $err) {
+ die 'Unable to determine network device for monitoring - ', $err;
+ }
+}
+
+my ($address, $netmask);
+my $object = Net::Pcap::open_live($dev, 1500, 0, 0, \$err);
+
+my $filter;
+Net::Pcap::compile(
+ $object,
+ \$filter,
+ #make your private network range in the filter below
+ '(not src net 192.168.0.0/16)',
+ 0,
+ $netmask
+) && die 'Unable to compile packet capture filter';
+
+Net::Pcap::setfilter($object, $filter) &&
+ die 'Unable to set packet capture filter';
+
+unless (defined $object) {
+ die 'Unable to create packet capture on device ', $dev, ' - ', $err;
+}
+
+#print $server "ticklex";
+
+Net::Pcap::loop($object, -1, \&packets, $server) ||
+ die 'Unable to perform packet capture';
+
+sub led_timeout {
+ my ($user_data, $pixel) = @_;
+ $led_timer[$pixel] = time() + 15;
+
+ for (my $i=0; $i<1024; $i++) {
+ if (($led_timer[$i] < time()) && ($led_timer[$i]>0)) {
+ print $user_data "R:$i,0";
+ print $user_data "G:$i,0";
+ print $user_data "B:$i,0";
+ $led_timer[$i] = 0;
+ }
+ }
+}
+
+sub ip2dec ($) {
+ unpack N => pack CCCC => split /\./ => shift;
+}
+
+sub packets {
+ my ($user_data, $header, $packet) = @_;
+ my $ether_data = NetPacket::Ethernet::strip($packet);
+ my $ip = NetPacket::IP->decode($ether_data);
+ my $num;
+ my $pixel;
+ my $intensity;
+ if($ip->{proto} == 6) {
+ my $tcp = NetPacket::TCP->decode($ip->{'data'});
+ if ($tcp) {
+ $num = $tcp->{'src_port'} / 64;
+ $pixel = floor($num);
+ $intensity = floor((((sprintf("%.2f",($num-$pixel))*100)) * 256) / 100);
+ print $user_data "R:$pixel,$intensity";
+ }
+ } elsif ($ip->{proto} == 17) {
+ my $udp = NetPacket::UDP->decode($ip->{'data'});
+ if ($udp) {
+ $num = $udp->{'src_port'} / 64;
+ $pixel = floor($num);
+ $intensity = floor((((sprintf("%.2f",($num-$pixel))*100)) * 256) / 100);
+ print $user_data "G:$pixel,$intensity";
+ }
+ } else {
+ $num = ip2dec($ip->{'src_ip'}) / 4194304;
+ $pixel = floor($num);
+ $intensity = floor((((sprintf("%.2f",($num-$pixel))*100)) * 256) / 100);
+ print $user_data "B:$pixel,$intensity";
+ }
+ led_timeout($user_data, $pixel);
+}