#!/usr/bin/perl
# Демон отвечающий за общение с базой.
#
# Запуск осуществляется:
#
# crdsrvz.pl [-d] [-h <host>] [<ttyS>], где:
#
# -d стартовать как демон
# -t <host> имя хоста для формирования имени таблиц исключений
# -l выводить сообщения через syslogd
# <ttyS> устройство unix socket для коннекта к crdsrvz.pl.
# по умолчанию ttyS1
require 'getopts.pl';
Getopts ('dlh:');
# Стартуем как демон, если указан ключик -d
if ($opt_d) {
$pid = fork();
die "can't fork: $!" unless defined $pid;
exit 0 if ($pid);
}
# use strict;
use Socket;
use Time::HiRes qw( sleep usleep );
use POSIX qw(strftime);
use Mysql;
my $port = 'ttyS1';
my $maxlen = 40;
my $dbhost="mysql";
my $dbbase="security";
my $dbuser="user";
my $dbpass="pass";
# Programs vars
$port = $ARGV[0] unless ($#ARGV < 0);
my $cardsock = "/tmp/card.$port";
# Part 0: Redefine interupt
$SIG{INT} = \&correct_quit;
$SIG{HUP} = \&correct_quit;
# Part: Connect to database
$|=1;
my $shortport = substr ($port, 3);
if (defined $opt_h) {
$id_host = $opt_h . $shortport . "\.";
} else {
$id_host = "hq" . $shortport . "\.";
}
# Part I: Start UNIX connection
socket (SERVER, PF_UNIX, SOCK_STREAM, 0);
connect (SERVER, sockaddr_un ($cardsock))
or correct_quit ("Can't connect to $cardsock: $!");
# Part III: Starting dialog
ctimestr ("Connection established...\n");
for (;;) {
sysread (SERVER, $answer, $maxlen) or correct_quit ("Can't received: $!\n");
chomp $answer;
(my $id, my $card) = split (" ", $answer);
my $id_name='';
my $id_room= $id_host . $id;
# Получаем запрос от cardserver и пытаемся подконнектиться к базе
local $dbh = Mysql->connect($dbhost, $dbbase, $dbuser, $dbpass) || correct_quit ("Can't connect: $DBI::errstr\n");
local $sth = $dbh->query("SELECT room, crosstable, level FROM rooms where id_room=\'$id_room\'\;");
($room, $crosstable, $roomlevel) = $sth->fetchrow;
my $action = "alarm"; my $name = "Грабитель";
# Засекаем время
$regtime = strftime "%Y%m%d%H%M%S", localtime();
# Обновляем запись для комнаты, где сигнализируем о последнем доступе
$sth = $dbh->query("UPDATE rooms SET touch=NOW() WHERE id_room=\"$id_room\"\;");
# Извлекаем id_name и level из базы карточек
$sth = $dbh->query("SELECT id_name, level FROM cards WHERE card=\"$card\"\;");
#sleep (15);
# Проверяем, есть ли такая карточка
if ($sth->affectedrows > 0) {
($id_name, $level) = $sth->fetchrow;
# Пытаемся отследить эту карточку, если она есть в базе
# $action="spy" unless (defined ($level) or (id_name eq 2));
$sth = $dbh->query("SELECT name FROM UBTC.persons WHERE id_name=\"$id_name\"\;");
# Если никого не нашли по этому id_name, пропускаем этот блок
if ($sth->affectedrows > 0) {
($name) = $sth->fetchrow;
$action="spy";
if (defined $roomlevel) {
$action = ($level <= $roomlevel) ? "open" : "close";
}
$sth = $dbh->query("UPDATE UBTC.persons SET id_name=$id_name,alast=$regtime WHERE id_name=$id_name\;");
# Проверяем таблицу исключений
$sth = $dbh->query("SELECT permit FROM $crosstable WHERE id_name=$id_name\;");
if ($sth->affectedrows > 0) { # Если есть записи - то предпринимаем соответствующие действия
($permit) = $sth->fetchrow;
$action = ($permit eq "yes") ? "open" : "close";
}
}
} else {
# Если нет, автоматически заносим в базу.
$sth = $dbh->query("INSERT INTO cards SET id_card=$regtime, card=\"$card\"\;");
}
# Протоколируем событие
$sth = $dbh->query("INSERT INTO journal SET regtime=$regtime, card=\"$card\", id_room=\"$id_room\", action=\"$action\", id_name=\'$id_name\'\;");
SWITCH: {
if ($action eq "open") {
$command = 1;
last SWITCH;
}
if ($action eq "close") {
$command = 2;
last SWITCH;
}
if ($action eq "spy") {
$command = 3;
last SWITCH;
}
if ($action eq "alarm") {
$command = 4;
$action .= " ($card)";
last SWITCH;
}
}
ctimestr ("ROOM: $room NAME: $name ACTION: $action\n");
defined syswrite (SERVER, "$id $command\n", 4) or correct_quit ("Can't send data: $!\n");
undef $sth;
undef $dbh;
}
sub ctimestr {
my @str = @_;
$timestr = strftime "%Y.%m.%d %H:%M:%S", localtime();
print "$timestr @str" unless ($opt_d);
}
sub correct_quit {
$warnmessage = shift;
# Part ...: Close UNIX socket
syswrite (SERVER, "quit", 4);
close (SERVER);
ctimestr ($warnmessage) if (defined $warnmessage);
if ($opt_l) {
}
exit;
}
понедельник, 26 февраля 2001 г.
Serial communications with an external device through ttyS (perl)
#!/usr/bin/perl
# Демон отвечающий за общение с ридерами посредством серийного порта.
# Он занимается исключительно ридерами и ничем больше.
#
# Зап
#
# crdsrvz.pl [-d] [-l] [<ttyS>], где:
#
# -d стартовать как демон
# -l logged into syslogd
# <ttyS> устройство серийного порта обозначенного в /dev. По умолчанию: ttyS1 (COM2)
require 'getopts.pl';
Getopts ('dl');
# Our program name
( my $program = $0 ) =~ s/^.*\///;
# Стартуем как демон, если указан ключик -d
if ($opt_d) {
$pid = fork();
die "can't fork: $!" unless defined $pid;
exit 0 if ($pid);
}
# use strict;
use Socket;
use Fcntl qw ( F_GETFL F_SETFL O_NONBLOCK );
use Device::SerialPort qw( :PARAM :STAT 0.07 );
use Time::HiRes qw( sleep usleep gettimeofday tv_interval );
use POSIX;
use Class::Struct qw( struct );
use Symbol;
use Sys::Syslog;
use vars qw( $PortObj @readers );
# Local vars
my $port = 'ttyS1';
my $baud = 1200;
my $parity = 'none';
my $facility = 'local1';
my $maxlen = 11; # Из сокета
my $start_tx = 0x02; my $end_tx = 0x03;
my $readers = 7;
my $quitphrase = "quit";
my $commandtimeout = 10;
# my $delaycycle = 100000;
my $delaycycle = 0.001;
my $skipcycles = 8;
my $red = 0x2;
my $green = 0x4;
my $soundalarm = $red + $green;
my $unlock = 0x8;
my $command_unlock = "1";
my $command_lock = "2";
my $command_spy = "3";
my $command_alarm = "4";
my $command_detect = "5";
my %msgs = (
detect => "Detect reader",
establ => "Connection established",
stconn => "Starting wait connect",
stcard => "Starting wait cards",
opdoor => "Door is opened on reader",
cldoor => "Door is closed on reader",
intsig => "Got interrupted signal",
slwarn => "WARNING! usleep not defined",
busy => "Reader still busy",
overbusy => "Reader busy time is over",
stop => "Reader stopping person",
alrm => "Detect strange card"
);
# Programs vars
$port = $ARGV[0] unless ($#ARGV < 0);
my $cardsock = "/tmp/card.$port";
my $lockfile = "/var/lock/LCK..$port";
struct Reader => {
addr => '$', # Адрес ридера
online => '$', # Подключен-ли физически
broke => '$', # Авария
card => '$', # Прочитанная карточка
busy => '$', # Занят - пропускаем
blink8 => '$', # Сигнал открытия замка
blink4 => '$', # Состояние лампочки green
blink2 => '$', # Состояние лампочки red
green => '$', # Можно проходить
red => '$', # Нельзя проходить
alrm => '$', # Сработал датчик
command => '$', # Поступившая комманда
timer => '$' # Таймер после последней комманды, карточки и т.п.
};
# Redefine __DIE__
sub die_quit {
$warnmessage = shift;
syslog_report ($warnmessage);
# Part ...: Close UNIX socket
# close ($server);
close (SERVER);
#
unlink $cardsock if (-e $cardsock);
# Part ...: Close serial device
readyall_turn(0);
#close ($PortObj);
# $PortObj->close if (defined $PortObj);
undef $PortObj if (defined $PortObj);
exit;
}
# Redifine QUIT
sub QUIT {
die_quit $msgs{intsig};
}
# Redefine interupt
$SIG{INT} = \&QUIT;
$SIG{HUP} = \&QUIT;
$SIG{__DIE__} = 'die_quit';
syslog_report ($msgs{slwarn}) unless defined &Time::HiRes::usleep;
# Init device
unlink $lockfile;
$PortObj = Device::SerialPort->new ("/dev/$port", TIOSDTR, $lockfile);
die "Can't open serial port $port: $!" unless (defined $PortObj);
$PortObj->read_const_time (10000);
$PortObj->baudrate ($baud);
$PortObj->parity ($parity);
$PortObj->databits (7);
$PortObj->handshake ('rst');
$PortObj->are_match (pack ("C", $end_tx));
# $PortObj->dtr_active(1);
# Start UNIX socket
socket (SERVER, PF_UNIX, SOCK_STREAM, 0);
# unlink $cardsock;
bind (SERVER, sockaddr_un ($cardsock)) or die "Can't create server: $!";
listen (SERVER, SOMAXCONN) or die "Couldn't listen on socket: $!";
# Allocate $readers listen servers;
@readers = ();
for ($id = 0; $id <= $readers; $id++) {
$readers[$id] = Reader->new();
$readers[$id]->addr($id * 0x10);
$readers[$id]->online(0);
$readers[$id]->blink8(0);
$readers[$id]->blink4(0);
$readers[$id]->blink2(0);
$readers[$id]->command(0);
$readers[$id]->broke(0);
($result) = ready_turn ($readers[$id], 0);
if (defined $result) {
syslog_report ("$id: " . $msgs{detect});
$readers[$id]->online (1);
}
}
# Система не обслуживается
# $readers[0]->online(0);
busyall_turn (1);
#############################################################################
# Primary cicle
#############################################################################
syslog_report ($msgs{stconn});
while (accept (CLIENT, SERVER)) {
# Взводим в исходное состояние все лазеры и все датчики
busyall_turn (0); resetall_turn (1);
syslog_report ($msgs{establ});
syslog_report ($msgs{stcard});
# Делаем сокет неблокирующим
Socket_Block (0);
my $gotit = ""; my $time0; my $elapsed;
while ($gotit ne $quitphrase) {
foreach $reader (@readers) {
# Проверяем - подключен ли ридер
next unless ($reader->online);
$id = $reader->addr / 16;
# Если он в аварийном состоянии
if ($reader->broke) {
($result) = broke_turn ($reader);
if ($result) {
$reader->broke(0);
}
next;
}
# Проверяем комманду и пытаемся ее выполнить
if ($reader->command) {
syslog_report ("$id: Command is " . $reader->command);
execute_command ($reader);
}
# Если пытаются пройти по "левой карточке"
if ($reader->alrm) {
alrm_turn ($reader);
$time0 = [gettimeofday]; $elapsed = tv_interval ($reader->timer, $time0);
$reader->alrm (0) if ($elapsed > $commandtimeout);
syslog_report ("$id: " . $msgs{alrm} . " left $elapsed");
next;
}
# Если ридер кого-то пропускает, то игнорируем датчик либо ждем срабатывания датчика,
if (my $times=$reader->green) {
unlock_door ($reader, 1) if ($times == $skipcycles);
if ($times > 1) {
$result = unlock_door ($reader, 0);
$times = (result) ? $times - 1 : 1;
$reader->green($times);
} else {
($result) = lock_door ($reader);
# Если датчик сработал, то взводимся в исходное состояние
if ($result) {
$reader->green(0);
syslog_report ("$id: " . $msgs{cldoor});
}
}
next;
}
# Если нельзя проходить ?
if ($reader->red) {
($result) = busy_turn ($reader, 1);
$time0 = [gettimeofday]; $elapsed = tv_interval ($reader->timer, $time0);
$reader->red(0) if ($elapsed > $commandtimeout);
syslog_report ("$id: " . $msgs{stop} . " left $elapsed");
# if ($result) {
# $reader->red (0); $reader->command (3);
# }
next;
}
my $card = "";
# Если ридер занят
if ($reader->busy) {
$time0 = [gettimeofday]; $elapsed = tv_interval ($reader->timer, $time0);
syslog_report ("$id: " . $msgs{busy} . " left $elapsed");
# Если истекло время занятости - вызываем бригаду ремонтников
if ($elapsed <= $commandtimeout) {
($result) = busy_turn ($reader);
} else {
syslog_report ("$id: " . $msgs{overbusy});
$reader->busy(0);
# $reader->broke(1);
}
next;
}
# Posle vseh proverok
# ($result, $card) = ready_turn ($reader, 1);
($result, $card) = ready_turn ($reader);
# Врубаем звуковой сигнал, если сработал датчик
unless ($result) {
$reader->command ($command_detect);
syslog_report ("$id: " . $msgs{opdoor});
next;
}
next unless (defined $card);
next if ($card eq "");
$card = $reader->card;
$time0 = [gettimeofday];
$reader->timer($time0);
$reader->busy (1);
# Пукнули для того, чтобы сказать, что карточка прочитана
# cardreaded_turn ($reader, 1);
my $msg = "Received $card(". length ($card) . ")";
syslog_report ("$id: " . $msg);
defined syswrite (CLIENT, "$id $card\n", $maxlen) or die "Can't send data: $!";
# Если увидели карточку - перестаем моргать
ready_turn ($reader, 0);
} # foreach $reader (@readers)
# Ждем либо карточку, либо команду с клиента
$when = sysread (CLIENT, $gotit, $maxlen);
if (defined $when) {
next if ($gotit eq $quitphrase);
# syslog_report ("Received answer: $gotit");
($id, $command) = split " ", $gotit;
$readers[$id]->command ($command);
} # if (defined $when)
# print "...Sleeping $delaycycle sec...\n";
# sleep ($delaycycle);
} # while ($gotit ne "quit")
# Тушим все лампочки и обнуляем все сигналы
foreach $reader (@readers) {
if ($reader->online) {
($result) = ready_turn ($reader, 0);
$reader->online (1) if (defined $result);
} else { next; }
$reader->busy (0); ready_turn ($reader, 0);
$reader->red(0); $reader->green (0); $reader->alrm (0); $reader->broke (0);
$reader->card ("");
}
busyall_turn (1);
# Делаем сокет блокирующим
Socket_Block (1);
syslog_report ($msgs{stconn});
}
exit 0;
#############################################################################
# All subroutines for this program
#############################################################################
sub execute_command {
local $reader = shift;
my $command = $reader->command;
my $time0 = [gettimeofday];
$reader->timer($time0);
SWITCH: {
# GREEN SIGNAL
if ($command eq $command_unlock) {
$reader->busy(0);
$reader->green($skipcycles);
last SWITCH;
}
# RED SIGNAL
if ($command eq $command_lock) {
$reader->busy(0);
$reader->red(1);
last SWITCH;
}
# SPY SIGNAL
if ($command eq $command_spy) {
$reader->busy(0);
$reader->red(1);
last SWITCH;
}
# ALARM SIGNAL
if ($command eq $command_alarm) {
$reader->busy(0);
$reader->green(0);
$reader->red(0);
$reader->alrm(1);
$reader->blink2(1);
$reader->blink4(0);
last SWITCH;
}
# DETECT SIGNAL
if ($command eq $command_detect) {
$reader->busy(0);
$reader->green(1);
last SWITCH;
}
}
$reader->command(0);
$reader->card("");
}
sub syslog_report {
my @str = @_;
if ($opt_l) {
# print "...logging into syslog...\n";
openlog($program, 'pid', $facility);
syslog ('info', "@str ");
closelog;
}
unless ($opt_d) {
$timestr = strftime "%Y.%m.%d %H:%M:%S", localtime();
print "$timestr @str \n";
}
}
sub Buffer_Clear {
my $verbose=shift;
$verbose=1 unless defined $verbose;
$PortObj->lookclear; $PortObj->input;
syslog_report ("ERROR: received illegal symbols") if $verbose;
}
sub waitfor {
my $timeout = $PortObj->get_tick_count + (1000 * shift);
# Ощищаем буффер приема
$PortObj->lookclear;
my $gotit = ""; my $found; my $end;
# Ждем ответ или вываливаемся по таймауту
for (;;) {
$gotit = $PortObj->lookfor;
return unless defined $gotit;
if ($gotit ne "") {
($found, $end) = $PortObj->lastlook;
return $gotit.$found;
}
return if ($PortObj->reset_error);
return if ($PortObj->get_tick_count > $timeout);
} # for
} # sub waitfor
sub alrm_turn {
local $reader = shift;
my $turn;
$turn1 = ($reader->blink2 == 1) ? 0 : 1;
$turn2 = ($reader->blink4 == 1) ? 0 : 1;
local $askreq = pack ("C", $reader->addr + $turn1 * $red + $turn2 * $green);
($status) = portexchange ($askreq);
$reader->blink2($turn1);
$reader->blink4($turn2);
return ($status);
}
sub broke_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink4 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * $soundalarm);
($status) = portexchange ($askreq);
$reader->blink4($turn);
$reader->blink2($turn);
return ($status);
}
sub reset_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink2 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * $unlock);
($status) = portexchange ($askreq);
$reader->blink8($turn);
return ($status);
}
sub busy_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink2 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * ($red));
($status) = portexchange ($askreq);
$reader->blink2($turn);
return ($status);
}
sub unlock_door {
local $reader = shift;
my $sound = shift;
$sound = 0 unless defined $sound;
my $turn = ($sound) ? $unlock + $soundalarm : $unlock + $green;
# Включаем
local $askreq = pack ("C", $reader->addr + $turn);
($status) = portexchange ($askreq);
$reader->blink8(1);
$reader->blink4($sound);
$reader->blink4(1);
return ($status);
}
sub lock_door {
local $reader = shift;
# Включаем
local $askreq = pack ("C", $reader->addr + $green);
($status) = portexchange ($askreq);
$reader->blink8(0);
return ($status);
}
sub cardreaded_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink8 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * ($red + $green));
($status) = portexchange ($askreq);
local $askreq = pack ("C", $reader->addr + $turn * ($red));
($status) = portexchange ($askreq);
$reader->blink2($turn);
return ($status);
}
sub ready_turn {
local $reader = shift;
my $turn = shift;
my $card = "";
$turn = ($reader->blink4 == 1) ? 0 : 1 unless defined $turn;
# Переключаем зеленую лампочку на ридере
local $askreq = pack ("C", $reader->addr + $turn * $green);
($status, $card) = portexchange ($askreq);
# Если оба undef - ридер не отвечает
return unless (defined ($card) and defined ($status));
$reader->blink4($turn);
# Если 8 пробелов - пропускаем
return ($status, "") if ($card =~ /\s{8}/);
$reader->card($card);
return ($status, $card);
}
sub portexchange {
my $askreq = shift;
my $status = 0;
my $verbose = 1;
local $card = "";
$PortObj->write ($askreq);
sleep ($delaycycle);
# read serial port
my $inport = waitfor (1);
# Проверяем состояние ридера на предмет наличия карточки
return unless defined $inport;
# Если $in < 0xb - у нас проблемы
unless (length ($inport) == 12) { Buffer_Clear($verbose); return ($status); }
# Получили каких-то 12 байт
# Выдираем номер карточки и все служебные символы
my @result = unpack ("C*", $inport);
$echocomm = $result[0]; $stx = $result[1]; $etx = $result[11];
unless ($echocomm == unpack ("C", $askreq)) { Buffer_Clear($verbose); return ($status); }
unless (($stx == $start_tx) and ($etx == $end_tx)) { Buffer_Clear($verbose); return ($status); }
$status = ($result[10] & 8) / 8;
$card = pack ("C*", @result [2..9]);
return (! $status, $card);
}
sub readyall_turn {
my $turn = shift;
local $reader;
foreach $reader (@readers) {
ready_turn ($reader, $turn) if $reader->online;
}
}
sub busyall_turn {
my $turn = shift;
local $reader;
foreach $reader (@readers) {
busy_turn ($reader, $turn) if ($reader->online);
}
}
sub resetall_turn {
my $turn = shift;
local $reader;
foreach $reader (@readers) {
reset_turn ($reader, $turn) if ($reader->online);
}
}
sub Socket_Block {
# Если $1 = 0 то сокет неблокирующий, иначе блокируется
my $block = shift;
my $flags = fcntl (CLIENT, F_GETFL, 0) or die "Can't get flags for the socket: $!";
$flags = ($block) ? ($flags | O_NONBLOCK) : ($flags + O_NONBLOCK);
$flags = fcntl (CLIENT, F_SETFL, $flags) or die "Can't set flags for the socket: $!";
return $flags;
}
# Демон отвечающий за общение с ридерами посредством серийного порта.
# Он занимается исключительно ридерами и ничем больше.
#
# Зап
#
# crdsrvz.pl [-d] [-l] [<ttyS>], где:
#
# -d стартовать как демон
# -l logged into syslogd
# <ttyS> устройство серийного порта обозначенного в /dev. По умолчанию: ttyS1 (COM2)
require 'getopts.pl';
Getopts ('dl');
# Our program name
( my $program = $0 ) =~ s/^.*\///;
# Стартуем как демон, если указан ключик -d
if ($opt_d) {
$pid = fork();
die "can't fork: $!" unless defined $pid;
exit 0 if ($pid);
}
# use strict;
use Socket;
use Fcntl qw ( F_GETFL F_SETFL O_NONBLOCK );
use Device::SerialPort qw( :PARAM :STAT 0.07 );
use Time::HiRes qw( sleep usleep gettimeofday tv_interval );
use POSIX;
use Class::Struct qw( struct );
use Symbol;
use Sys::Syslog;
use vars qw( $PortObj @readers );
# Local vars
my $port = 'ttyS1';
my $baud = 1200;
my $parity = 'none';
my $facility = 'local1';
my $maxlen = 11; # Из сокета
my $start_tx = 0x02; my $end_tx = 0x03;
my $readers = 7;
my $quitphrase = "quit";
my $commandtimeout = 10;
# my $delaycycle = 100000;
my $delaycycle = 0.001;
my $skipcycles = 8;
my $red = 0x2;
my $green = 0x4;
my $soundalarm = $red + $green;
my $unlock = 0x8;
my $command_unlock = "1";
my $command_lock = "2";
my $command_spy = "3";
my $command_alarm = "4";
my $command_detect = "5";
my %msgs = (
detect => "Detect reader",
establ => "Connection established",
stconn => "Starting wait connect",
stcard => "Starting wait cards",
opdoor => "Door is opened on reader",
cldoor => "Door is closed on reader",
intsig => "Got interrupted signal",
slwarn => "WARNING! usleep not defined",
busy => "Reader still busy",
overbusy => "Reader busy time is over",
stop => "Reader stopping person",
alrm => "Detect strange card"
);
# Programs vars
$port = $ARGV[0] unless ($#ARGV < 0);
my $cardsock = "/tmp/card.$port";
my $lockfile = "/var/lock/LCK..$port";
struct Reader => {
addr => '$', # Адрес ридера
online => '$', # Подключен-ли физически
broke => '$', # Авария
card => '$', # Прочитанная карточка
busy => '$', # Занят - пропускаем
blink8 => '$', # Сигнал открытия замка
blink4 => '$', # Состояние лампочки green
blink2 => '$', # Состояние лампочки red
green => '$', # Можно проходить
red => '$', # Нельзя проходить
alrm => '$', # Сработал датчик
command => '$', # Поступившая комманда
timer => '$' # Таймер после последней комманды, карточки и т.п.
};
# Redefine __DIE__
sub die_quit {
$warnmessage = shift;
syslog_report ($warnmessage);
# Part ...: Close UNIX socket
# close ($server);
close (SERVER);
#
unlink $cardsock if (-e $cardsock);
# Part ...: Close serial device
readyall_turn(0);
#close ($PortObj);
# $PortObj->close if (defined $PortObj);
undef $PortObj if (defined $PortObj);
exit;
}
# Redifine QUIT
sub QUIT {
die_quit $msgs{intsig};
}
# Redefine interupt
$SIG{INT} = \&QUIT;
$SIG{HUP} = \&QUIT;
$SIG{__DIE__} = 'die_quit';
syslog_report ($msgs{slwarn}) unless defined &Time::HiRes::usleep;
# Init device
unlink $lockfile;
$PortObj = Device::SerialPort->new ("/dev/$port", TIOSDTR, $lockfile);
die "Can't open serial port $port: $!" unless (defined $PortObj);
$PortObj->read_const_time (10000);
$PortObj->baudrate ($baud);
$PortObj->parity ($parity);
$PortObj->databits (7);
$PortObj->handshake ('rst');
$PortObj->are_match (pack ("C", $end_tx));
# $PortObj->dtr_active(1);
# Start UNIX socket
socket (SERVER, PF_UNIX, SOCK_STREAM, 0);
# unlink $cardsock;
bind (SERVER, sockaddr_un ($cardsock)) or die "Can't create server: $!";
listen (SERVER, SOMAXCONN) or die "Couldn't listen on socket: $!";
# Allocate $readers listen servers;
@readers = ();
for ($id = 0; $id <= $readers; $id++) {
$readers[$id] = Reader->new();
$readers[$id]->addr($id * 0x10);
$readers[$id]->online(0);
$readers[$id]->blink8(0);
$readers[$id]->blink4(0);
$readers[$id]->blink2(0);
$readers[$id]->command(0);
$readers[$id]->broke(0);
($result) = ready_turn ($readers[$id], 0);
if (defined $result) {
syslog_report ("$id: " . $msgs{detect});
$readers[$id]->online (1);
}
}
# Система не обслуживается
# $readers[0]->online(0);
busyall_turn (1);
#############################################################################
# Primary cicle
#############################################################################
syslog_report ($msgs{stconn});
while (accept (CLIENT, SERVER)) {
# Взводим в исходное состояние все лазеры и все датчики
busyall_turn (0); resetall_turn (1);
syslog_report ($msgs{establ});
syslog_report ($msgs{stcard});
# Делаем сокет неблокирующим
Socket_Block (0);
my $gotit = ""; my $time0; my $elapsed;
while ($gotit ne $quitphrase) {
foreach $reader (@readers) {
# Проверяем - подключен ли ридер
next unless ($reader->online);
$id = $reader->addr / 16;
# Если он в аварийном состоянии
if ($reader->broke) {
($result) = broke_turn ($reader);
if ($result) {
$reader->broke(0);
}
next;
}
# Проверяем комманду и пытаемся ее выполнить
if ($reader->command) {
syslog_report ("$id: Command is " . $reader->command);
execute_command ($reader);
}
# Если пытаются пройти по "левой карточке"
if ($reader->alrm) {
alrm_turn ($reader);
$time0 = [gettimeofday]; $elapsed = tv_interval ($reader->timer, $time0);
$reader->alrm (0) if ($elapsed > $commandtimeout);
syslog_report ("$id: " . $msgs{alrm} . " left $elapsed");
next;
}
# Если ридер кого-то пропускает, то игнорируем датчик либо ждем срабатывания датчика,
if (my $times=$reader->green) {
unlock_door ($reader, 1) if ($times == $skipcycles);
if ($times > 1) {
$result = unlock_door ($reader, 0);
$times = (result) ? $times - 1 : 1;
$reader->green($times);
} else {
($result) = lock_door ($reader);
# Если датчик сработал, то взводимся в исходное состояние
if ($result) {
$reader->green(0);
syslog_report ("$id: " . $msgs{cldoor});
}
}
next;
}
# Если нельзя проходить ?
if ($reader->red) {
($result) = busy_turn ($reader, 1);
$time0 = [gettimeofday]; $elapsed = tv_interval ($reader->timer, $time0);
$reader->red(0) if ($elapsed > $commandtimeout);
syslog_report ("$id: " . $msgs{stop} . " left $elapsed");
# if ($result) {
# $reader->red (0); $reader->command (3);
# }
next;
}
my $card = "";
# Если ридер занят
if ($reader->busy) {
$time0 = [gettimeofday]; $elapsed = tv_interval ($reader->timer, $time0);
syslog_report ("$id: " . $msgs{busy} . " left $elapsed");
# Если истекло время занятости - вызываем бригаду ремонтников
if ($elapsed <= $commandtimeout) {
($result) = busy_turn ($reader);
} else {
syslog_report ("$id: " . $msgs{overbusy});
$reader->busy(0);
# $reader->broke(1);
}
next;
}
# Posle vseh proverok
# ($result, $card) = ready_turn ($reader, 1);
($result, $card) = ready_turn ($reader);
# Врубаем звуковой сигнал, если сработал датчик
unless ($result) {
$reader->command ($command_detect);
syslog_report ("$id: " . $msgs{opdoor});
next;
}
next unless (defined $card);
next if ($card eq "");
$card = $reader->card;
$time0 = [gettimeofday];
$reader->timer($time0);
$reader->busy (1);
# Пукнули для того, чтобы сказать, что карточка прочитана
# cardreaded_turn ($reader, 1);
my $msg = "Received $card(". length ($card) . ")";
syslog_report ("$id: " . $msg);
defined syswrite (CLIENT, "$id $card\n", $maxlen) or die "Can't send data: $!";
# Если увидели карточку - перестаем моргать
ready_turn ($reader, 0);
} # foreach $reader (@readers)
# Ждем либо карточку, либо команду с клиента
$when = sysread (CLIENT, $gotit, $maxlen);
if (defined $when) {
next if ($gotit eq $quitphrase);
# syslog_report ("Received answer: $gotit");
($id, $command) = split " ", $gotit;
$readers[$id]->command ($command);
} # if (defined $when)
# print "...Sleeping $delaycycle sec...\n";
# sleep ($delaycycle);
} # while ($gotit ne "quit")
# Тушим все лампочки и обнуляем все сигналы
foreach $reader (@readers) {
if ($reader->online) {
($result) = ready_turn ($reader, 0);
$reader->online (1) if (defined $result);
} else { next; }
$reader->busy (0); ready_turn ($reader, 0);
$reader->red(0); $reader->green (0); $reader->alrm (0); $reader->broke (0);
$reader->card ("");
}
busyall_turn (1);
# Делаем сокет блокирующим
Socket_Block (1);
syslog_report ($msgs{stconn});
}
exit 0;
#############################################################################
# All subroutines for this program
#############################################################################
sub execute_command {
local $reader = shift;
my $command = $reader->command;
my $time0 = [gettimeofday];
$reader->timer($time0);
SWITCH: {
# GREEN SIGNAL
if ($command eq $command_unlock) {
$reader->busy(0);
$reader->green($skipcycles);
last SWITCH;
}
# RED SIGNAL
if ($command eq $command_lock) {
$reader->busy(0);
$reader->red(1);
last SWITCH;
}
# SPY SIGNAL
if ($command eq $command_spy) {
$reader->busy(0);
$reader->red(1);
last SWITCH;
}
# ALARM SIGNAL
if ($command eq $command_alarm) {
$reader->busy(0);
$reader->green(0);
$reader->red(0);
$reader->alrm(1);
$reader->blink2(1);
$reader->blink4(0);
last SWITCH;
}
# DETECT SIGNAL
if ($command eq $command_detect) {
$reader->busy(0);
$reader->green(1);
last SWITCH;
}
}
$reader->command(0);
$reader->card("");
}
sub syslog_report {
my @str = @_;
if ($opt_l) {
# print "...logging into syslog...\n";
openlog($program, 'pid', $facility);
syslog ('info', "@str ");
closelog;
}
unless ($opt_d) {
$timestr = strftime "%Y.%m.%d %H:%M:%S", localtime();
print "$timestr @str \n";
}
}
sub Buffer_Clear {
my $verbose=shift;
$verbose=1 unless defined $verbose;
$PortObj->lookclear; $PortObj->input;
syslog_report ("ERROR: received illegal symbols") if $verbose;
}
sub waitfor {
my $timeout = $PortObj->get_tick_count + (1000 * shift);
# Ощищаем буффер приема
$PortObj->lookclear;
my $gotit = ""; my $found; my $end;
# Ждем ответ или вываливаемся по таймауту
for (;;) {
$gotit = $PortObj->lookfor;
return unless defined $gotit;
if ($gotit ne "") {
($found, $end) = $PortObj->lastlook;
return $gotit.$found;
}
return if ($PortObj->reset_error);
return if ($PortObj->get_tick_count > $timeout);
} # for
} # sub waitfor
sub alrm_turn {
local $reader = shift;
my $turn;
$turn1 = ($reader->blink2 == 1) ? 0 : 1;
$turn2 = ($reader->blink4 == 1) ? 0 : 1;
local $askreq = pack ("C", $reader->addr + $turn1 * $red + $turn2 * $green);
($status) = portexchange ($askreq);
$reader->blink2($turn1);
$reader->blink4($turn2);
return ($status);
}
sub broke_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink4 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * $soundalarm);
($status) = portexchange ($askreq);
$reader->blink4($turn);
$reader->blink2($turn);
return ($status);
}
sub reset_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink2 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * $unlock);
($status) = portexchange ($askreq);
$reader->blink8($turn);
return ($status);
}
sub busy_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink2 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * ($red));
($status) = portexchange ($askreq);
$reader->blink2($turn);
return ($status);
}
sub unlock_door {
local $reader = shift;
my $sound = shift;
$sound = 0 unless defined $sound;
my $turn = ($sound) ? $unlock + $soundalarm : $unlock + $green;
# Включаем
local $askreq = pack ("C", $reader->addr + $turn);
($status) = portexchange ($askreq);
$reader->blink8(1);
$reader->blink4($sound);
$reader->blink4(1);
return ($status);
}
sub lock_door {
local $reader = shift;
# Включаем
local $askreq = pack ("C", $reader->addr + $green);
($status) = portexchange ($askreq);
$reader->blink8(0);
return ($status);
}
sub cardreaded_turn {
local $reader = shift;
my $turn = shift;
$turn = ($reader->blink8 == 1) ? 0 : 1 unless defined $turn;
local $askreq = pack ("C", $reader->addr + $turn * ($red + $green));
($status) = portexchange ($askreq);
local $askreq = pack ("C", $reader->addr + $turn * ($red));
($status) = portexchange ($askreq);
$reader->blink2($turn);
return ($status);
}
sub ready_turn {
local $reader = shift;
my $turn = shift;
my $card = "";
$turn = ($reader->blink4 == 1) ? 0 : 1 unless defined $turn;
# Переключаем зеленую лампочку на ридере
local $askreq = pack ("C", $reader->addr + $turn * $green);
($status, $card) = portexchange ($askreq);
# Если оба undef - ридер не отвечает
return unless (defined ($card) and defined ($status));
$reader->blink4($turn);
# Если 8 пробелов - пропускаем
return ($status, "") if ($card =~ /\s{8}/);
$reader->card($card);
return ($status, $card);
}
sub portexchange {
my $askreq = shift;
my $status = 0;
my $verbose = 1;
local $card = "";
$PortObj->write ($askreq);
sleep ($delaycycle);
# read serial port
my $inport = waitfor (1);
# Проверяем состояние ридера на предмет наличия карточки
return unless defined $inport;
# Если $in < 0xb - у нас проблемы
unless (length ($inport) == 12) { Buffer_Clear($verbose); return ($status); }
# Получили каких-то 12 байт
# Выдираем номер карточки и все служебные символы
my @result = unpack ("C*", $inport);
$echocomm = $result[0]; $stx = $result[1]; $etx = $result[11];
unless ($echocomm == unpack ("C", $askreq)) { Buffer_Clear($verbose); return ($status); }
unless (($stx == $start_tx) and ($etx == $end_tx)) { Buffer_Clear($verbose); return ($status); }
$status = ($result[10] & 8) / 8;
$card = pack ("C*", @result [2..9]);
return (! $status, $card);
}
sub readyall_turn {
my $turn = shift;
local $reader;
foreach $reader (@readers) {
ready_turn ($reader, $turn) if $reader->online;
}
}
sub busyall_turn {
my $turn = shift;
local $reader;
foreach $reader (@readers) {
busy_turn ($reader, $turn) if ($reader->online);
}
}
sub resetall_turn {
my $turn = shift;
local $reader;
foreach $reader (@readers) {
reset_turn ($reader, $turn) if ($reader->online);
}
}
sub Socket_Block {
# Если $1 = 0 то сокет неблокирующий, иначе блокируется
my $block = shift;
my $flags = fcntl (CLIENT, F_GETFL, 0) or die "Can't get flags for the socket: $!";
$flags = ($block) ? ($flags | O_NONBLOCK) : ($flags + O_NONBLOCK);
$flags = fcntl (CLIENT, F_SETFL, $flags) or die "Can't set flags for the socket: $!";
return $flags;
}
Подписаться на:
Комментарии (Atom)