#!/usr/bin/perl

use IO::Socket;
use Data::Dumper;
use Data::Hexdumper;

$atem_ip   = "79.140.38.124";
#$atem_ip   = "127.0.0.1";
$atem_port = "9910";

$sock = IO::Socket::INET->new(
		Proto => 'udp',
		PeerPort => $atem_port,
		PeerAddr => $atem_ip
)  || die "Socket fail: $@";

$uid   = (((rand(254) + 1) << 8) + rand(254) + 1) & 0x7FFF;
$data  = pack("nnnn", 0x0100, 0x0000, 0x0000, 0x0000);
$hello = pack("CCnnnnna*", 0x10, 0x14, $uid, 0, 0, 0x0026, 0, $data);

$sock->send($hello);

$mycnt = 0;

$hello_finished = 0;

while($sock->recv($data, 4096)) {
	print "\n";
	($cmd, $len, $uid, $cnt_out, $unkn1, $unkn2, $cnt_in, $payload) = unpack("CCnnnnna*", $data);
	($port, $ipaddr) = sockaddr_in($sock->peername);
	$len = (($cmd & 0x07) << 8) + $len;
	$cmd = $cmd & 0xF8;

	if ($hello_finished) {
		print rhexdump($data, "<");
	}

	printf("CMD: %02X - LEN: %4d (%03X) - UID: %04X\n",
		$cmd, $len, $len, $uid);
	printf("CNT_OUT: %04X - CNT_IN: %04X - UNKN1: %04X - UNKN2: %04X\n",
		$cnt_out, $cnt_in, $unkn1, $unkn2);

	$rcmd = 0;

	if ($cmd & 0x10) {
		# hello response
		(undef, $new_uid, undef, undef) = unpack("nnnn", $payload);
		send_pkt(0x80, $uid, 0, 0, 0x00e9, 0, '');
	}

	if ($cmd & 0x08) {
		if ($cnt_in == 0x0a && $hello_finished == 0) {
			$hello_finished = 1;
			$mycnt++;
		}
		if ($hello_finished) {
			send_pkt(0x80, $uid, $cnt_in, 0, 0, 0, '');
			send_pkt(0x08, $uid, 0, 0, 0, $mycnt, '');
			$mycnt++;
		}
	}

	if ($mycnt == 0 && $hello_finished != 0) {
		$cmd = 0x80;
	}

	#if ($cmd & 0x80) {
	#	$mycnt++;
	#}

	if ($mycnt > 0 && ($mycnt % 5) == 0) {
		$channel++;
		if ($channel > 14) {
			$channel = 0;
		}
		if ($channel == 13) {
			$channel++;
		}

		$keyer++;
		if ($keyer > 5) {
			$keyer = 1;
		}

		print("Switch to " . $channel . "\n");

		#$rpayload = '000c00004350764900'.sprintf("%02X", $channel).'0000';
		#send_pkt(0x08, $uid, 0, 0, 0, $mycnt, pack("H*", $rpayload));
		#$mycnt++;

		#$rpayload = '000c00004350674900'.sprintf("%02X", $channel).'0000';
		#send_pkt(0x08, $uid, 0, 0, 0, $mycnt, pack("H*", $rpayload));
		#$mycnt++;

		$rpayload  = '000c00004350764900'.sprintf("%02X", $channel).'0000';
		$rpayload .= '000c00004350674900'.sprintf("%02X", $channel).'0000';
		$rpayload .= '000c000043545470020003'.sprintf("%02X", (1 << ($keyer - 1)));
		$rpayload .= '000c0000435454700100'.sprintf("%02X", (5 - $keyer)).'00';
		send_pkt(0x08, $uid, 0, 0, 0, $mycnt, pack("H*", $rpayload));
		$mycnt++;
	}
}

sub send_pkt {
	my $cmd     = shift;
	my $uid     = shift;
	my $cout    = shift;
	my $un1     = shift;
	my $un2     = shift;
	my $cin     = shift;
	my $payload = shift;

	my $len = 12 + length($payload);
	$cmd = $cmd + (($len >> 8) & 0x07);

	my $pkt = pack("CCnnnnna*", $cmd, $len, $uid, $cout, $un1, $un2, $cin, $payload);
	print rhexdump($pkt, ">");
	$sock->send($pkt);
}

	($cmd, $len, $uid, $cnt_out, $unkn1, $unkn2, $cnt_in, $payload) = unpack("CCnnnnna*", $data);



sub rhexdump {
	my $input  = shift;
	my $prefix = shift;

	my $ret = "";
	my $i = 0;
	my $j = 0;
	my @lhs = ();
	my @rhs = ();

	if (!$prefix) {
		$prefix = " ";
	}

	my @chars = split('', $input);
	for ($i = 0; $i <= $#chars; $i++) {
		my $token = ord($chars[$i]);
		$lhs[$j] .= sprintf(" %02X", $token);
		if ($token >= 0x20 && $token <= 0x7E) {
			$rhs[$j] .= sprintf("%c", $token);
		} else {
			$rhs[$j] .= ".";
		}
		if ((($i + 1) % 8) == 0) {
			$lhs[$j] .= " ";
			$rhs[$j] .= " ";
		}
		if ((($i + 1) % 16) == 0) {
			$lhs[$j] = substr($lhs[$j], 0, -1);
			$rhs[$j] = substr($rhs[$j], 0, -1);
			$j++;
		}
	}

	my $len = length($lhs[-1]);
	if ($len > 0 && $len != 49) {
		$lhs[-1] .= (" " x (49 - $len));
		$rhs[-1] .= (" " x (17 - ($len / 3)));
	}

	for ($i = 0; $i <= $#lhs; $i++) {
		$ret .= sprintf("%s %04X %s  |%s|\n", $prefix, ($i * 16), $lhs[$i], $rhs[$i]);
	}

	return($ret);
}

exit 0;
