Initial commit
commit
c5cfbf4ecb
@ -0,0 +1,152 @@
|
||||
##############################################
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
use IPC::Open2;
|
||||
|
||||
sub FHZ_Write($$$);
|
||||
sub FHZ_Read($);
|
||||
sub FHZ_Ready($);
|
||||
|
||||
sub
|
||||
EB_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
# Provider
|
||||
$hash->{ReadyFn} = "EB_Ready";
|
||||
$hash->{ReadFn} = "EB_Read";
|
||||
$hash->{WriteFn} = "EB_Write";
|
||||
$hash->{Clients} = ":EB:EBN:";
|
||||
|
||||
my %mc = (
|
||||
"1:EBN" => "^R",
|
||||
);
|
||||
$hash->{MatchList} = \%mc;
|
||||
|
||||
# Normal devices
|
||||
$hash->{DefFn} = "EB_Define";
|
||||
$hash->{UndefFn} = "EB_Undef";
|
||||
$hash->{SetFn} = "EB_Set";
|
||||
$hash->{AttrList}= "loglevel:0,1,2,3,4,5,6";
|
||||
}
|
||||
|
||||
sub
|
||||
EB_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
Log 3, "$hash->{NAME} define ";
|
||||
if(@a < 3 || @a > 3) {
|
||||
my $msg = "wrong syntax: define <name> EB {devicename}";
|
||||
Log 2, $msg;
|
||||
Log 2, @a;
|
||||
return $msg;
|
||||
}
|
||||
my $name = $a[0];
|
||||
my $dev = $a[2];
|
||||
|
||||
$hash->{DeviceName} = $dev;
|
||||
|
||||
my($pid, $chld_out, $chld_in);
|
||||
$pid = open2($chld_out, $chld_in, '/root/ebd -d '.$dev);
|
||||
|
||||
$hash->{RDPIPE} = $chld_out;
|
||||
$hash->{WRPIPE} = $chld_in;
|
||||
$hash->{FD} = fileno($chld_out);
|
||||
$hash->{PID} = $pid;
|
||||
$hash->{STATE} = "Open";
|
||||
$selectlist{"$name.pipe"} = $hash;
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
EB_Undef($$)
|
||||
{
|
||||
my ($hash, $arg) = @_;
|
||||
|
||||
Log 3, "$hash->{NAME} undef";
|
||||
return if ($hash->{STATE} ne "Open");
|
||||
|
||||
EB_Write($hash,'Q','');
|
||||
|
||||
kill $hash->{PID};
|
||||
close($hash->{RDPIPE});
|
||||
close($hash->{WRPIPE});
|
||||
|
||||
delete $hash->{FD};
|
||||
delete $hash->{RDPIPE};
|
||||
delete $hash->{WRPIPE};
|
||||
delete $hash->{PID};
|
||||
|
||||
$hash->{STATE} = "Closed";
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
EB_Ready($)
|
||||
{
|
||||
my ($hash,$fn,$msg) = @_;
|
||||
Log 5, "$hash->{NAME} ready";
|
||||
return 1;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
EB_Write($$$)
|
||||
{
|
||||
my ($hash,$fn,$msg) = @_;
|
||||
my ($buf);
|
||||
|
||||
$buf = $fn . ' ' . $msg;
|
||||
Log 5, "$hash->{NAME} write: " . $buf;
|
||||
$buf .= "\n";
|
||||
syswrite($hash->{WRPIPE}, $buf);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
EB_Read($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my ($buf, $res, $nextbyte);
|
||||
|
||||
|
||||
CHAR: while (sysread($hash->{RDPIPE}, $nextbyte, 1)) {
|
||||
last CHAR if $nextbyte eq "\n";
|
||||
$buf .= $nextbyte;
|
||||
}
|
||||
|
||||
Log 5, "$hash->{NAME} read: " . $buf;
|
||||
$hash->{RAWMSG} = $buf;
|
||||
Dispatch($hash, $buf, undef);
|
||||
return $buf;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
EB_Set($@)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
|
||||
my $name = shift @a;
|
||||
my $type = shift @a;
|
||||
my $arg = join(" ", @a);
|
||||
|
||||
return "Unknown argument $type, choose one of raw" if($type ne "raw");
|
||||
|
||||
$arg .= "\n";
|
||||
|
||||
syswrite($hash->{WRPIPE}, $arg);
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,292 @@
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub
|
||||
EBN_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = "^R";
|
||||
$hash->{DefFn} = "EBN_Define";
|
||||
$hash->{ParseFn} = "EBN_Parse";
|
||||
$hash->{GetFn} = "EBN_Get";
|
||||
$hash->{SetFn} = "EBN_Set";
|
||||
$hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5,6";
|
||||
|
||||
}
|
||||
|
||||
#############################
|
||||
sub
|
||||
EBN_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
my $u = "wrong syntax: define <name> EBN addr type";
|
||||
|
||||
return "wrong syntax: define <name> EBN addr type" if(int(@a) != 4);
|
||||
|
||||
$modules{EBN}{defptr}{$a[2]} = $hash;
|
||||
$hash->{STATE} = "Defined";
|
||||
$hash->{EBTYPE} = $a[3];
|
||||
$hash->{ADDR} = $a[2];
|
||||
$hash->{channel1} = "Init";
|
||||
AssignIoPort($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub
|
||||
EBN_Parse($$)
|
||||
{
|
||||
my ($hash, $msg) = @_;
|
||||
|
||||
# Msg format: R addr chan value
|
||||
my @cmp = split(" ", $msg);
|
||||
my $def = $modules{EBN}{defptr}{$cmp[1]};
|
||||
my $changed;
|
||||
my $log;
|
||||
my $v1;
|
||||
my $v2;
|
||||
my $v3;
|
||||
my $v4;
|
||||
|
||||
Log 5, "$hash->{NAME} parse: " . $msg;
|
||||
|
||||
if($def) {
|
||||
my $name = $def->{NAME};
|
||||
if ($cmp[2] == 0) {
|
||||
IOWrite($def, "R", $cmp[1]. " 1 0");
|
||||
return $name;
|
||||
}
|
||||
|
||||
# TYPE 1: Test Node
|
||||
# Channel 1:
|
||||
# Bit 0 : Test LED
|
||||
# Bit 1 : Exp LED
|
||||
# Channel 2:
|
||||
# Vcc
|
||||
|
||||
$changed = 0;
|
||||
$v1 = $cmp[3] & 0x1;
|
||||
$v2 = $cmp[3] & 0x2;
|
||||
$v3 = $cmp[3] & 0x4;
|
||||
$v4 = $cmp[3] & 0x8;
|
||||
|
||||
if ($def->{EBTYPE} == 1) {
|
||||
if ($cmp[2] == 1) {
|
||||
if (($v1 != ($def->{channel1} & 0x1)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{testled}{TIME} = TimeNow();
|
||||
$def->{READINGS}{testled}{VAL} = $v1 ? "on" : "off";
|
||||
$changed = 1;
|
||||
}
|
||||
if (($v2 != ($def->{channel1} & 0x2)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{expled}{TIME} = TimeNow();
|
||||
$def->{READINGS}{expled}{VAL} = $v2 ? "on" : "off";
|
||||
$changed = 1;
|
||||
}
|
||||
if ($def->{channel1} eq "Init") {
|
||||
IOWrite($def, "R", $cmp[1]. " 2 0");
|
||||
}
|
||||
$def->{channel1} = $cmp[3];
|
||||
if ($changed == 1) {
|
||||
$log = "testled: " . ($v1 ? "on" : "off") . " expled: " . ($v2 ? "on" : "off");
|
||||
$def->{STATE} = $log;
|
||||
push @{$def->{CHANGED}}, $log;
|
||||
DoTrigger($def->{NAME}, undef);
|
||||
}
|
||||
}
|
||||
if ($cmp[2] == 2) {
|
||||
$def->{READINGS}{vcc}{TIME} = TimeNow();
|
||||
$def->{READINGS}{vcc}{VAL} = $cmp[3];
|
||||
}
|
||||
}
|
||||
|
||||
# TYPE 2: Alarm Node
|
||||
# Channel 1:
|
||||
# Bit 0 : Tuerkontakt
|
||||
# Bit 1 : Buzzer aus
|
||||
# Channel 2:
|
||||
# Vcc
|
||||
|
||||
if ($def->{EBTYPE} == 2) {
|
||||
if ($cmp[2] == 1) {
|
||||
if (($v1 != ($def->{channel1} & 0x1)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{tuer}{TIME} = TimeNow();
|
||||
$def->{READINGS}{tuer}{VAL} = $v1 ? "closed" : "open";
|
||||
$changed = 1;
|
||||
}
|
||||
if (($v2 != ($def->{channel1} & 0x2)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{buzzer}{TIME} = TimeNow();
|
||||
$def->{READINGS}{buzzer}{VAL} = $v2 ? "disabled" : "enabled";
|
||||
$changed = 1;
|
||||
}
|
||||
if ($def->{channel1} eq "Init") {
|
||||
IOWrite($def, "R", $cmp[1]. " 2 0");
|
||||
}
|
||||
$def->{channel1} = $cmp[3];
|
||||
if ($changed == 1) {
|
||||
$log = "tuer: ". ($v1 ? "closed" : "open") . " buzzer: " . ($v2 ? "disabled" : "enabled");
|
||||
$def->{STATE} = $log;
|
||||
push @{$def->{CHANGED}}, $log;
|
||||
DoTrigger($def->{NAME}, undef);
|
||||
}
|
||||
}
|
||||
if ($cmp[2] == 2) {
|
||||
$def->{READINGS}{vcc}{TIME} = TimeNow();
|
||||
$def->{READINGS}{vcc}{VAL} = $cmp[3];
|
||||
}
|
||||
}
|
||||
|
||||
# TYPE 3: Relais Node
|
||||
# Channel 1:
|
||||
# Bit 0 : LED
|
||||
# Bit 1 : Relais 1
|
||||
# Bit 2 : Relais 2
|
||||
|
||||
if ($def->{EBTYPE} == 3) {
|
||||
if ($cmp[2] == 1) {
|
||||
if (($v1 != ($def->{channel1} & 0x1)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{led}{TIME} = TimeNow();
|
||||
$def->{READINGS}{led}{VAL} = $v1 ? "on": "off";
|
||||
$changed = 1;
|
||||
}
|
||||
if (($v2 != ($def->{channel1} & 0x2)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{relais1}{TIME} = TimeNow();
|
||||
$def->{READINGS}{relais1}{VAL} = $v2 ? "on": "off";
|
||||
$changed = 1;
|
||||
}
|
||||
if (($v3 != ($def->{channel1} & 0x4)) || ($def->{channel1} eq "Init")) {
|
||||
$def->{READINGS}{relais2}{TIME} = TimeNow();
|
||||
$def->{READINGS}{relais2}{VAL} = $v3 ? "on": "off";
|
||||
$changed = 1;
|
||||
}
|
||||
$def->{channel1} = $cmp[3];
|
||||
if ($changed == 1) {
|
||||
$log = "led: " . ($v1 ? "on": "off") . " relais1: " . ($v2 ? "on": "off") . " relais2: " . ($v3? "on": "off");
|
||||
$def->{STATE} = $log;
|
||||
push @{$def->{CHANGED}}, $log;
|
||||
DoTrigger($def->{NAME}, undef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $name;
|
||||
} else {
|
||||
Log 3, "EBN Unknown device $cmp[1], please define it";
|
||||
if ($cmp[2] == 0) {
|
||||
return "UNDEFINED EBN_$cmp[1] EBN $cmp[1] $cmp[3]";
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub
|
||||
EBN_Get($@)
|
||||
{
|
||||
my ($hash, @args) = @_;
|
||||
|
||||
return 'EBN_Get needs two arguments' if (@args != 2);
|
||||
|
||||
my $get = $args[1];
|
||||
my $val;
|
||||
|
||||
if ( $get eq "?"){
|
||||
if ($hash->{EBTYPE} == 1) {
|
||||
return "Unknown argument ?, choose one of testled expled";
|
||||
}
|
||||
if ($hash->{EBTYPE} == 2) {
|
||||
return "Unknown argument ?, choose one of tuer buzzer";
|
||||
}
|
||||
if ($hash->{EBTYPE} == 3) {
|
||||
return "Unknown argument ?, choose one of led relais1 relais2";
|
||||
}
|
||||
return "EBN_Get: no such reading: $get";
|
||||
}
|
||||
if (defined($hash->{READINGS}{$get})) {
|
||||
$val = $hash->{READINGS}{$get}{VAL};
|
||||
} else {
|
||||
return "EBN_Get: no such reading: $get";
|
||||
}
|
||||
Log 3, "$args[0] $get => $val";
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
sub
|
||||
EBN_Set($@)
|
||||
{
|
||||
my ($hash, @args) = @_;
|
||||
|
||||
my $set = $args[1];
|
||||
my $num;
|
||||
my $msg;
|
||||
|
||||
if ( $set eq "?"){
|
||||
if ($hash->{EBTYPE} == 1) {
|
||||
return "Unknown argument ?, choose one of testled expled";
|
||||
}
|
||||
if ($hash->{EBTYPE} == 2) {
|
||||
return "Unknown argument ?, choose one of buzzer";
|
||||
}
|
||||
if ($hash->{EBTYPE} == 3) {
|
||||
return "Unknown argument ?, choose one of led relais1 relais2";
|
||||
}
|
||||
return "EBN_Get: no such reading: $set";
|
||||
}
|
||||
return 'EBN_Set needs three arguments' if (@args != 3);
|
||||
my $val = $args[2];
|
||||
|
||||
Log 3, "$args[0] $set => $val";
|
||||
|
||||
if ($hash->{EBTYPE} == 1) {
|
||||
if ($val eq "on") {
|
||||
$num = 1;
|
||||
} else {
|
||||
$num = 0;
|
||||
}
|
||||
if ($set eq "testled") {
|
||||
$msg = ($hash->{channel1} & 0x3FE) | $num;
|
||||
}
|
||||
if ($set eq "expled") {
|
||||
$msg = ($hash->{channel1} & 0x3FD) | ($num << 1);
|
||||
}
|
||||
IOWrite($hash, "W", $hash->{ADDR} . " 1 " . $msg);
|
||||
}
|
||||
if ($hash->{EBTYPE} == 2) {
|
||||
if ($val eq "disabled") {
|
||||
$num = 1;
|
||||
} else {
|
||||
$num = 0;
|
||||
}
|
||||
if ($set eq "buzzer") {
|
||||
$msg = ($hash->{channel1} & 0x3FD) | ($num << 1);
|
||||
}
|
||||
IOWrite($hash, "W", $hash->{ADDR} . " 1 " . $msg);
|
||||
}
|
||||
if (($hash->{EBTYPE} == 3) || ($hash->{EBTYPE} == 4)) {
|
||||
if ($val eq "on") {
|
||||
$num = 1;
|
||||
} else {
|
||||
$num = 0;
|
||||
}
|
||||
if ($set eq "led") {
|
||||
$msg = ($hash->{channel1} & 0x3FE) | $num;
|
||||
}
|
||||
if ($set eq "relais1") {
|
||||
$msg = ($hash->{channel1} & 0x3FD) | ($num << 1);
|
||||
}
|
||||
if ($set eq "relais2") {
|
||||
$msg = ($hash->{channel1} & 0x3FB) | ($num << 2);
|
||||
}
|
||||
IOWrite($hash, "W", $hash->{ADDR} . " 1 " . $msg);
|
||||
}
|
||||
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -0,0 +1 @@
|
||||
SUBDIRS = src
|
@ -0,0 +1,15 @@
|
||||
AC_INIT([src/rs485.c])
|
||||
AC_PREREQ([2.63])
|
||||
AM_INIT_AUTOMAKE(ebd, 0.0.1)
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
@ -0,0 +1,6 @@
|
||||
bin_PROGRAMS = ebd
|
||||
|
||||
AM_CFLAGS = $(DEPS_CFLAGS)
|
||||
|
||||
ebd_SOURCES = main.c rs485.c
|
||||
ebd_LDADD = $(DEPS_LIBS)
|
@ -0,0 +1,245 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <strings.h>
|
||||
|
||||
void send_ack(int addr) {
|
||||
unsigned char buf[16];
|
||||
|
||||
buf[0] = 0xAA;
|
||||
buf[1] = 2;
|
||||
buf[2] = addr;
|
||||
buf[3] = addr;
|
||||
buf[4] = 1;
|
||||
buf[5] = 1;
|
||||
buf[6] = 0;
|
||||
buf[7] = 0;
|
||||
buf[8] = 0;
|
||||
buf[9] = 0;
|
||||
buf[10] = 0;
|
||||
buf[11] = 0;
|
||||
buf[12] = 0;
|
||||
buf[13] = 0;
|
||||
buf[14] = 0;
|
||||
|
||||
rs485_crc(buf);
|
||||
rs485_send(buf);
|
||||
}
|
||||
|
||||
void send_read_req(int addr, int channel) {
|
||||
unsigned char buf[16];
|
||||
|
||||
buf[0] = 0xAA;
|
||||
buf[1] = 0;
|
||||
buf[2] = addr;
|
||||
buf[3] = addr;
|
||||
buf[4] = 1;
|
||||
buf[5] = 1;
|
||||
buf[6] = 0x40 + channel;
|
||||
buf[7] = 0;
|
||||
buf[8] = 0;
|
||||
buf[9] = 0;
|
||||
buf[10] = 0;
|
||||
buf[11] = 0;
|
||||
buf[12] = 0;
|
||||
buf[13] = 0;
|
||||
buf[14] = 0;
|
||||
|
||||
rs485_crc(buf);
|
||||
rs485_send(buf);
|
||||
}
|
||||
|
||||
void send_write_req(int addr, int channel, int data) {
|
||||
unsigned char buf[16];
|
||||
|
||||
buf[0] = 0xAA;
|
||||
buf[1] = 0;
|
||||
buf[2] = addr;
|
||||
buf[3] = addr;
|
||||
buf[4] = 1;
|
||||
buf[5] = 1;
|
||||
buf[6] = 0x60 + channel + ((data & 0x300 ) >> 5);
|
||||
buf[7] = data & 0xFF;
|
||||
buf[8] = 0;
|
||||
buf[9] = 0;
|
||||
buf[10] = 0;
|
||||
buf[11] = 0;
|
||||
buf[12] = 0;
|
||||
buf[13] = 0;
|
||||
buf[14] = 0;
|
||||
|
||||
rs485_crc(buf);
|
||||
rs485_send(buf);
|
||||
}
|
||||
|
||||
void send_poll(void) {
|
||||
unsigned char buf[16];
|
||||
|
||||
buf[0] = 0xAA;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = 1;
|
||||
buf[5] = 1;
|
||||
buf[6] = 0;
|
||||
buf[7] = 0;
|
||||
buf[8] = 0;
|
||||
buf[9] = 0;
|
||||
buf[10] = 0;
|
||||
buf[11] = 0;
|
||||
buf[12] = 0;
|
||||
buf[13] = 0;
|
||||
buf[14] = 0;
|
||||
|
||||
rs485_crc(buf);
|
||||
rs485_send(buf);
|
||||
}
|
||||
|
||||
void mainloop(int fd) {
|
||||
struct timeval timeout;
|
||||
int rd;
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
fd_set eset;
|
||||
int quit;
|
||||
int alt;
|
||||
int ret;
|
||||
int req_dev;
|
||||
int req_channel;
|
||||
int req_data;
|
||||
int req_write;
|
||||
int ack_dev;
|
||||
int dev_poll;
|
||||
unsigned char rbuf[16];
|
||||
|
||||
alt = 0;
|
||||
quit = 0;
|
||||
req_dev = 0;
|
||||
req_channel = 0;
|
||||
ack_dev = 0;
|
||||
dev_poll = 2;
|
||||
|
||||
while (!quit) {
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&eset);
|
||||
FD_SET(fd, &rset);
|
||||
FD_SET(0, &rset);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 40000;
|
||||
|
||||
rd = select(fd + 1, &rset, &wset, &eset, &timeout);
|
||||
|
||||
if (rd == 0) {
|
||||
if (alt) {
|
||||
send_poll();
|
||||
alt = 0;
|
||||
continue;
|
||||
}
|
||||
alt = 1;
|
||||
|
||||
if (ack_dev) {
|
||||
send_ack(ack_dev);
|
||||
ack_dev = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (req_dev) {
|
||||
if (req_write)
|
||||
send_write_req(req_dev, req_channel, req_data);
|
||||
else
|
||||
send_read_req(req_dev, req_channel);
|
||||
req_dev = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
send_read_req(dev_poll, 0);
|
||||
dev_poll++;
|
||||
if (dev_poll > 126)
|
||||
dev_poll = 2;
|
||||
} else {
|
||||
if (FD_ISSET(fd, &rset)) {
|
||||
ret = rs485_recv_loop();
|
||||
if (ret < 0)
|
||||
exit(-1);
|
||||
if (ret == 0)
|
||||
continue;
|
||||
|
||||
rs485_recv(&rbuf);
|
||||
|
||||
if ((rbuf[1] == 1) && (rbuf[2] == 1))
|
||||
ack_dev = rbuf[4];
|
||||
|
||||
if ((rbuf[2] == 1) && (rbuf[6] >= 0x40) && (rbuf[6] < 0x60)) {
|
||||
printf ("R %d %d %d\n", rbuf[4], (rbuf[6] - 0x40) & 0x7, rbuf[7] + (((rbuf[6] - 0x40) & 0x18) << 5));
|
||||
fflush(stdout);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(0, &rset)) {
|
||||
unsigned char a;
|
||||
unsigned char ibuf[100];
|
||||
int d, c, v;
|
||||
unsigned char *p;
|
||||
|
||||
p = fgets(ibuf, 100, stdin);
|
||||
if (p == NULL)
|
||||
exit(-1);
|
||||
|
||||
sscanf(ibuf, "%c %d %d %d\n", &a, &d, &c, &v);
|
||||
if (a == 'Q') {
|
||||
quit = 1;
|
||||
continue;
|
||||
}
|
||||
if (a == 'R') {
|
||||
req_dev = d;
|
||||
req_channel = c;
|
||||
req_write = 0;
|
||||
continue;
|
||||
}
|
||||
if (a == 'W') {
|
||||
req_dev = d;
|
||||
req_channel = c;
|
||||
req_data = v;
|
||||
req_write = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
char *dev = "/dev/ttyS2";
|
||||
int c;
|
||||
|
||||
int fd;
|
||||
|
||||
while ((c = getopt(argc, argv, "d:")) != -1)
|
||||
switch (c) {
|
||||
case 'd':
|
||||
dev = optarg;
|
||||
break;
|
||||
}
|
||||
|
||||
fd = rs485_open(dev);
|
||||
if (fd < 0) {
|
||||
printf("RS485 open failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mainloop(fd);
|
||||
|
||||
rs485_close();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
#include <linux/serial.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <strings.h>
|
||||
|
||||
/* Driver-specific ioctls: */
|
||||
#define TIOCGRS485 0x542E
|
||||
#define TIOCSRS485 0x542F
|
||||
|
||||
struct serial_rs485 rs485conf;
|
||||
struct termios options;
|
||||
|
||||
int fd;
|
||||
unsigned char inbuf[16];
|
||||
int bufp;
|
||||
|
||||
static uint16_t crc_ccitt_update(uint16_t crc, uint8_t data)
|
||||
{
|
||||
data ^= (crc & 0xFF);
|
||||
data ^= data << 4;
|
||||
|
||||
return ((((uint16_t)data << 8) | ((crc >> 8) & 0xFF))
|
||||
^ (uint8_t)(data >> 4) ^ ((uint16_t)data << 3));
|
||||
}
|
||||
|
||||
int rs485_crc(unsigned char buf[16])
|
||||
{
|
||||
uint16_t crc;
|
||||
int i;
|
||||
|
||||
if (buf[0] != 0xAA)
|
||||
return -1;
|
||||
if (buf[2] != buf[3])
|
||||
return -1;
|
||||
if (buf[4] != buf[5])
|
||||
return -1;
|
||||
|
||||
crc = 0xFFFF;
|
||||
for (i=0; i<14; i++)
|
||||
crc = crc_ccitt_update(crc, buf[i]);
|
||||
buf[14] = (crc >> 8) & 0xFF;
|
||||
buf[15] = crc & 0xFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rs485_send(unsigned char buf[16])
|
||||
{
|
||||
return write(fd, buf, 16);
|
||||
}
|
||||
|
||||
int rs485_recv(unsigned char buf[16])
|
||||
{
|
||||
int i;
|
||||
if (bufp < 16)
|
||||
return -1;
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
buf[i] = inbuf[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rs485_recv_loop(void)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p;
|
||||
uint16_t crc;
|
||||
|
||||
if (bufp >=16)
|
||||
bufp=0;
|
||||
|
||||
p = &(inbuf[bufp]);
|
||||
|
||||
if (read(fd, p, 1) < 0)
|
||||
return -1;
|
||||
|
||||
bufp++;
|
||||
|
||||
if ((bufp == 1) && (inbuf[0] != 0xAA))
|
||||
bufp = 0;
|
||||
|
||||
if ((bufp == 4) && (inbuf[2] != inbuf[3]))
|
||||
bufp = 0;
|
||||
|
||||
if ((bufp == 6) && (inbuf[4] != inbuf[5]))
|
||||
bufp = 0;
|
||||
|
||||
if (bufp == 16) {
|
||||
crc = 0xFFFF;
|
||||
|
||||
for (i=0; i<14; i++)
|
||||
crc = crc_ccitt_update(crc, inbuf[i]);
|
||||
if ((inbuf[14] == ((crc >> 8) & 0xFF)) && (inbuf[15] == (crc & 0xFF)))
|
||||
return 1;
|
||||
else
|
||||
bufp = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rs485_close(void)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int rs485_open(char *path)
|
||||
{
|
||||
fd = open (path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rs485conf.flags |= SER_RS485_ENABLED;
|
||||
rs485conf.flags |= (SER_RS485_RTS_ON_SEND);
|
||||
rs485conf.flags |= (SER_RS485_RTS_AFTER_SEND);
|
||||
//rs485conf.flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
ioctl (fd, TIOCSRS485, &rs485conf);
|
||||
|
||||
bzero(&options, sizeof(options));
|
||||
cfsetspeed(&options, B9600);
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS8;
|
||||
options.c_cflag |= (CLOCAL | CREAD);
|
||||
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
||||
options.c_oflag &= ~OPOST;
|
||||
options.c_cc[VMIN] = 0;
|
||||
options.c_cc[VTIME] = 1;
|
||||
tcflush(fd,TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &options);
|
||||
|
||||
return fd;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
int rs485_crc(unsigned char buf[16]);
|
||||
int rs485_send(unsigned char buf[16]);
|
||||
int rs485_recv(unsigned char buf[16]);
|
||||
int rs485_recv_loop(void);
|
||||
int rs485_close(void);
|
||||
int rs485_open(char *path);
|
Loading…
Reference in New Issue