#!/usr/bin/env perl

use strict;

use Time::HiRes qw(time);
use Graphics::Framebuffer;
use List::Util qw(max);

$SIG{'QUIT'} = sub { exec('reset'); };
$SIG{'INT'}  = sub { exec('reset'); };
$SIG{'KILL'} = sub { exec('reset'); };

my $args = join('', @ARGV);

my $dev = 0;
if ($args =~ /(\d+)/) {
    $dev = $1;
}

my @f;
$f[0] = Graphics::Framebuffer->new('FILE_MODE' => 0, 'FB_DEVICE' => "/dev/fb$dev");

$f[1] = Graphics::Framebuffer->new('FILE_MODE' => 1, 'FB_DEVICE' => "/dev/fb$dev", 'SPLASH' => 0);

$f[0]->cls('OFF');
my @t;
my $x        = $f[0]->{'XRES'} / 2;
my $y        = $f[0]->{'YRES'} / 2;
my $max_time = 10;
my $master;
my $count;

foreach $count (0 .. 1) {
    $f[$count]->cls();
    my $bench = 0;
    my $start = time + $max_time;
    $master = int(rand(16777216));
    while (time < $start) {
        $f[$count]->set_color(ncolor());
        $f[$count]->circle({ 'x' => $x, 'y' => $y, 'radius' => $y - 1, 'filled' => 1 });
        $bench++;
    }

    push(@t, $bench);
} ## end foreach $count (0 .. 1)
foreach $count (0 .. 1) {
    $f[$count]->cls();
    my $bench = 0;
    my $start = time + $max_time;
    $master = int(rand(16777216));
    while (time < $start) {
        $f[$count]->set_color(ncolor());
        $f[$count]->box({ 'x' => 0, 'y' => 0, 'xx' => $f[0]->{'XRES'}, 'yy' => $f[0]->{'YRES'}, 'filled' => 1 });
        $bench++;
    }

    push(@t, $bench);
} ## end foreach $count (0 .. 1)
foreach $count (0 .. 1) {
    $f[$count]->cls();
    my $bench = 0;
    my $start = time + $max_time;
    $master = int(rand(16777216));
    while (time < $start) {
        $f[$count]->set_color(ncolor());
        $f[$count]->line({ 'x' => 0, 'y' => 0, 'xx' => $f[0]->{'XRES'}, 'yy' => $f[0]->{'YRES'} });
        $bench++;
    }
    push(@t, $bench);
} ## end foreach $count (0 .. 1)

$f[0]->cls('ON');
my @names = ('CIRCLE', 'CIRCLE', '   BOX', '   BOX', '  LINE', '  LINE');
print STDERR "The higher the number, the faster it is.\n\n";

my $file_average   = 0;
my $string_average = 0;
for (my $idx = 0; $idx < 6; $idx += 2) {
    if ($t[$idx] > $t[$idx + 1]) {
        print STDERR sprintf('%s MMAP:  %d (fastest)', $names[$idx], $t[$idx]), "\n";
        print STDERR sprintf('%s FILE:  %d', $names[$idx + 1], $t[$idx + 1]), "\n\n";
    } elsif ($t[$idx] < $t[$idx + 1]) {
        print STDERR sprintf('%s MMAP:  %d', $names[$idx], $t[$idx]), "\n";
        print STDERR sprintf('%s FILE:  %d (fastest)', $names[$idx + 1], $t[$idx + 1]), "\n\n";
    } else {
        print STDERR sprintf('%s MMAP:  %d', $names[$idx], $t[$idx]), "\n";
        print STDERR sprintf('%s FILE:  %d', $names[$idx + 1], $t[$idx + 1]), "\n\n";
    }
    $string_average += $t[$idx];
    $file_average   += $t[$idx + 1];
} ## end for (my $idx = 0; $idx ...)

$file_average   /= 3;
$string_average /= 3;

print STDERR sprintf('Memory Mapped String Mode Average: %.03f', $string_average), "\n";
print STDERR sprintf('         File Handle Mode Average: %.03f', $file_average),   "\n\n";

if ($file_average <= $string_average) {
    print STDERR "It is recommended you use the default Mmap string mode for your framebuffer device.\n";
} else {
    print STDERR "It is recommend you use the File Handle mode for your framebuffer device, UNLESS you will be using the 'replace_color' method a lot\n";
}

sub ncolor {
    my $temp = pack('L', $master);
    my ($red, $green, $blue) = unpack('C3', $temp);
    $master += 8;
    return ({ 'red' => $red, 'green' => $green, 'blue' => $blue });
} ## end sub ncolor

=head1 NAME

Memory Mapped versus File Handle test

=head1 DESCRIPTION

Tests the framebuffer device to see whether memory mapped string mode or direct file handle mode is faster for the specific device.

Usually memory mapped mode is faster, but SOME TFT modules with SPI interfaces are considersably faster in file handle mode.

=head1 SYNOPSIS

 perl mmapvsfile.pl [device number]

=head1 OPTION

=over 2

=item C<device number>

The framebuffer device number to use (default 0)

=back

=head2 Example

=over 4

 perl mmapvsfile.pl 1

=back

=cut
