C and PERL communicating via keyboard status lights
My friend and I got inspired by this one last night.
We use Perl for the sender program and C for the receiver.
The medium of exchange was the keybord status lights!
Three virtual signal lines were used: Caps Lock, Num Lock and Scroll lock, being used as Clock, Serial Data, and Start Of Byte signals.
The sender program pulses those keyboard lights and the receiver polls them and checks the state. Data is sent serially as binary, in 8 bit bytes.
You can see the transmitter and receiver programs in operation, in the attached video, as well as the flashing of the lights during the transmission.
Video of operation
Source for both programs is attached. Given the question requirements, we didn't try to minimize the size like we would in a normal golfing attempt.
C Code (receiver)
#include <X11/Xlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
Display* dpy = XOpenDisplay(":0");
XKeyboardState x;
char keys_return[32];
int b = 0;
while (1) {
unsigned char output = 0;
printf(" \b");
fflush(stdout);
while (XQueryKeymap(dpy, keys_return)) //wait for start signal
if (keys_return[9] == 64) {
break;
}
for (b = 0; b < 8; b++) {
do {
XGetKeyboardControl(dpy, &x);
} while (!(x.led_mask & 1)); //wait for clock to be high
if (x.led_mask & 2)
output |= 128;
if (b != 7)
output >>= 1;
do {
XGetKeyboardControl(dpy, &x);
} while ((x.led_mask & 1)); //wait for clock to be low
}
printf("%c", output);
}
XCloseDisplay(dpy);
return 0;
}
PERL code (transmitter)
use X11::Xlib ':all';
use strict;
use warnings;
use feature 'say';
use Time::HiRes qw(sleep);
use constant {
DATA => 77,
START => 78,
CLOCK => 66
};
my $display = X11::Xlib->new;
sub transmit_str {
my ($str) = @_;
foreach my $char ( split( //, $str ) ) {
my $ordchar = ord($char);
for my $i ( 0 .. 7 ) {
for my $j ( 0 .. 1 ) {
if ( $i == 0 ) {
$display->fake_key( START, !($j) );
}
if ( $ordchar & 1 ) {
$display->fake_key( DATA, 1 );
$display->fake_key( DATA, 0 );
}
$display->flush;
sleep(0.025) if(!$j);
$display->fake_key( CLOCK, 1 );
$display->fake_key( CLOCK, 0 );
$display->flush;
sleep(0.05);
}
$ordchar >>= 1;
}
}
}
while ( my $stdin = <STDIN> ) {
transmit_str($stdin);
}