Initial commit

master
Jochen Friedrich 10 years ago
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…
Cancel
Save